BZOJ4665 : 小w的喜糖

考虑枚举哪些人一定不合法,那么方案数可以通过简单的排列组合算出。

于是设$f[i][j]$表示前$i$种糖果,一共有$j$个人一定不合法的方案数,但是这样并不能保证其他人一定合法,所以需要进行容斥。

最后将答案除以每种糖果数量的阶乘,即可保证本质不同。

时间复杂度$O(n^2)$。

#include<cstdio>
const int N=2005,P=1000000009;
int n,i,j,k,x,a[N],C[N][N],fac[N],inv[N],f[N][N],tmp,ans;
int main(){
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&x),a[x]++;
for(C[0][0]=i=1;i<=n;i++)for(C[i][0]=j=1;j<=i;j++)C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
for(fac[0]=fac[1]=inv[0]=inv[1]=1,i=2;i<=n;i++){
fac[i]=1LL*fac[i-1]*i%P;
inv[i]=1LL*(P-inv[P%i])*(P/i)%P;
}
for(i=2;i<=n;i++)inv[i]=1LL*inv[i]*inv[i-1]%P;
for(f[0][0]=i=1;i<=n;i++)for(j=0;j<=n;j++)for(k=0;k<=a[i]&&k<=j;k++)
f[i][j]=(1LL*f[i-1][j-k]*C[a[i]][k]%P*fac[a[i]]%P*inv[a[i]-k]+f[i][j])%P;
for(i=0;i<=n;i++){
tmp=1LL*f[n][i]*fac[n-i]%P;
if(i&1)ans=(ans-tmp+P)%P;else ans=(ans+tmp)%P;
}
for(i=1;i<=n;i++)ans=1LL*ans*inv[a[i]]%P;
return printf("%d",ans),0;
}

  

上一篇:Eclipse关联JavaDoc和源代码


下一篇:Linux下你需要了解的10个网络和监控命令