题意
求 (1 sim n) 的排列,有 (m) 个限制条件,第 (i) 个限制条件 (p_i) 表示前 (p_i) 个数不能是 (1sim p_i) 的排列,求符合要求的排列的个数。答案对 (20000311) 取模。
链接:https://ac.nowcoder.com/acm/contest/7745/C
(nleq 2000, m,p_i<n)
分析
首先定于状态:(dp[i]) 表示处理到第 (p_i) 个数时,前 (i-1) 个条件满足而第 (i) 个条件不满足的方案数。这个状态定义很重要,方便后面去重。
那么答案就是:
[ans=n!-sum_{i=1}^{m}{dp[i] imes (n-p[i])!}
]
显然,(dp[1]=fac[p[1]]) ,(dp[2]=fac[p[2]]-dp[1]*fac[p[2]-p[1]]),其它的以此类推。
代码
#include <bits/stdc++.h>
using namespace std;
const int mod=20000311;
const int N=2010;
int dp[N],fac[N],p[N];
void init()
{
int maxn=2000;
fac[0]=1;
for(int i=1;i<=maxn;i++)
fac[i]=1LL*fac[i-1]*i%mod;
}
int main()
{
init();
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d",&p[i]);
sort(p+1,p+1+m);
dp[1]=fac[p[1]];
for(int i=2;i<=m;i++)
{
dp[i]=fac[p[i]];
for(int j=1;j<i;j++)
dp[i]=(dp[i]-1LL*dp[j]*fac[p[i]-p[j]]%mod+mod)%mod;
}
int ans=fac[n];
for(int i=1;i<=m;i++)
ans=(ans-1LL*dp[i]*fac[n-p[i]]%mod+mod)%mod;
printf("%d
",ans);
return 0;
}