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;
}

  

posted @ 2016-08-22 19:30  Claris  阅读(343)  评论(0编辑  收藏  举报