链接:https://ac.nowcoder.com/acm/contest/7745/C
来源:牛客网
数学考试
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
牛牛在树剖姐姐的数学考试里出了一个题,但是树剖姐姐不会做,于是她向您求助。
求 1∼n1\sim n1∼n 的排列,有 m 个限制条件,第i个限制条件 pip_ipi 表示前 pip_ipi 个数不能是 1∼pi1\sim p_i1∼pi 的排列,求符合要求的排列的个数。
答案对 20000311 取模。
输入描述:
第一行两个 n,m 第二行 m 个数,每两个数之间用一个空格隔开,第i个数是pi,保证pi互不相同
输出描述:
一个数,表示符合要求的排列个数对 20000311 取模的结果
示例1
输入
4 0
输出
24
示例2
输入
3 2 2 1
输出
3
说明
3 1 2,3 2 1,2 3 1三种合法
示例3
输入
4 2 1 3
输出
14
示例4
输入
114 5 14 1 91 98 10
输出
19843522
(f[i]为i!)用dp[i]表示前 i - 1 个条件满足、第 i 个条件满足的方案数,它等于所有排列 p[i]! 减去不合法的情况,计算不合法的情况时枚举j,dp[j]即为第 j 个条件不满足、前 j - 1个条件满足,所以 dp[i] = p[i]! - dp[j] * f[p[i] - p[j]],f[p[i] - p[j]]为p[j]~p[i]全排,即这一部分对整个1~p[i]的合法性无关了,可以随便排。
扫描二维码关注公众号,回复:
11923884 查看本文章
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 20000311;
const int inf = 0x3f3f3f3f;
const int N = 2e3 + 7;
ll p[N], dp[N], f[N];
void init() {
f[0] = 1;
for(ll i = 1; i < N; ++i)
f[i] = f[i - 1] * i % mod;
}
int main() {
init();
ll n, m;
scanf("%lld%lld", &n, &m);
for(ll i = 1; i <= m; ++i) {
scanf("%lld", &p[i]);
}
p[m + 1] = n;
sort(p + 1, p + m + 1);
for(ll i = 1; i <= m + 1; ++i) {
dp[i] = f[p[i]];
for(ll j = 1; j < i; ++j)
dp[i] = (dp[i] - dp[j] * f[p[i] - p[j]] % mod + mod) % mod;
}
printf("%lld\n", dp[m + 1] % mod);
return 0;
}