BZOJ 4710: [Jsoi2011]分特产(容斥)

传送门

解题思路

  首先所有物品是一定要用完的,那么可以按照物品考虑,就是把每种物品分给\(n\)个人,每个人分得非负整数,可以用隔板法计算。设物品有\(m\)个,方案数为\(C(n+m-1,n-1)\)。但这样会有人一个也分不到的情况,就容斥一下。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;
typedef long long LL;
const int N=2005;
const int MOD=1e9+7;

inline int rd(){
	int x=0,f=1; char ch=getchar();
	while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
	while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return f?x:-x;	
}

int n,m,C[N][N],a[N],ans;

inline void prework(){
	C[0][0]=1;
	for(int i=1;i<=2000;++i){
		C[i][0]=1;
		for(int j=1;j<=i;++j)
			C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;	
	}
}

int main(){
	n=rd(),m=rd(); prework(); int now;
	for(int i=1;i<=m;++i) a[i]=rd();
	for(int i=0;i<n;++i){
		now=C[n][i];
		for(int j=1;j<=m;++j)
			now=1ll*now*C[a[j]+n-i-1][n-i-1]%MOD;
		if(i&1) (ans-=now)%=MOD;
		else (ans+=now)%=MOD;
	}
	printf("%d\n",(ans+MOD)%MOD);
	return 0;
}	
posted @ 2019-02-18 10:47  Monster_Qi  阅读(137)  评论(0编辑  收藏  举报