BZOJ 4665: 小w的喜糖【dp,容斥

80 篇文章 0 订阅
20 篇文章 0 订阅

……QwQ做的第一发这种题

f[i][j]表示分配了前i种,至少有j个人不合法,然后容斥一下就好

最后统计的时候,剩下的n-j个人的分配方法是(n-j)!除以每种糖剩余数量的阶乘的积,这个积直接在dp的时候算好


#include<bits/stdc++.h>
#define MOD 1000000009
#define MAXN 2005
using namespace std;	int n;
int x[MAXN];
int C[MAXN][MAXN];
int jc[MAXN],_jc[MAXN];

int f[MAXN][MAXN];

inline int POW(long long d,long long c){
	long long rtn=1;
	for(;c;c>>=1,d=d*d%MOD)
		if(c&1)	rtn=rtn*d%MOD;
	return (int)rtn;
}

inline void Plus(int &a,const int b){
	a+=b;
	if(a<0)	a+=MOD;
	if(a>=MOD)	a-=MOD;
}

inline void init(){
	C[0][0]=1;
	for(register int i=1,j;i<=n;++i)
		for(j=1,C[i][0]=1;j<=i;++j)
			C[i][j]=C[i-1][j-1],Plus(C[i][j],C[i-1][j]);
	jc[0]=1;
	for(register int i=1;i<=n;++i)	jc[i]=1ll*jc[i-1]*i%MOD;
	_jc[n]=POW(jc[n],MOD-2);
	for(register int i=n-1;~i;--i)	_jc[i]=1ll*_jc[i+1]*(i+1)%MOD;
}

int read_x;
int main(){
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	scanf("%d",&n);
	
	init();
	for(int i=1;i<=n;++i)	scanf("%d",&read_x),++x[read_x];
	int tot=0;
	f[0][0]=1;
	for(int i=1;i<=n;tot+=x[i++])
		for(int j=0;j<=tot;++j)
			for(int k=0;k<=x[i];++k)
				Plus(f[i][j+k],1ll*f[i-1][j]*C[x[i]][k]%MOD*_jc[x[i]-k]%MOD);//,printf("f[ %d ][ %d ] = %d\n",i,j+k,f[i][j+k]);
	int ans=0;
//	for(int i=0;i<=tot;++i)	printf("%d\n",f[n][i]);
	for(int i=0;i<=tot;++i)
		Plus(ans,(i&1?-1ll:1ll)*f[n][i]*jc[tot-i]%MOD);
	printf("%d",ans);
	return 0;
}




  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值