【牛客练习赛71C】数学考试

题目

题目链接:https://ac.nowcoder.com/acm/contest/7745/C
牛牛在树剖姐姐的数学考试里出了一个题,但是树剖姐姐不会做,于是她向您求助。
\(1\sim n\) 的排列,有 \(m\) 个限制条件,第 \(i\) 个限制条件 \(p_i\) 表示前 \(p_i\) 个数不能是 \(1\sim p_i\) 的排列,求符合要求的排列的个数。
答案对 20000311 取模。

思路

先将 \(p\) 从小到大排序。
\(f[i]\) 表示满足了第 \(i\) 个条件的方案数。枚举上一次满足的条件,考虑容斥。

\[f[i]=-\sum^{i-1}_{j=1}f[j]\times (p[i]-p[j])! \]

时间复杂度 \(O(m^2)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=2010,MOD=20000311;
int n,m,p[N];
ll f[N],fac[N];

int main()
{
	scanf("%d%d",&n,&m);
	fac[0]=1;
	for (int i=1;i<=n;i++)
		fac[i]=fac[i-1]*i%MOD;
	for (int i=1;i<=m;i++)
		scanf("%d",&p[i]);
	p[++m]=n; p[++m]=0; f[1]=1;
	sort(p+1,p+1+m);
	for (int i=1;i<=m;i++)
		for (int j=1;j<i;j++)
			f[i]=(f[i]-f[j]*fac[p[i]-p[j]])%MOD;
	printf("%lld",(-f[m]%MOD+MOD)%MOD);
	return 0;
}

原文地址:https://www.cnblogs.com/stoorz/p/13789903.html