BZOJ - 4710 分特产
JYY 带队参加了若干场ACM/ICPC 比赛,带回了许多土特产,要分给实验室的同学们。
JYY 想知道,把这些特产分给N 个同学,一共有多少种不同的分法?当然,JYY 不希望任
何一个同学因为没有拿到特产而感到失落,所以每个同学都必须至少分得一个特产。
例如,JYY 带来了2 袋麻花和1 袋包子,分给A 和B 两位同学,那么共有4 种不同的
分配方法:
A:麻花,B:麻花、包子
A:麻花、麻花,B:包子
A:包子,B:麻花、麻花
A:麻花、包子,B:麻花
Input
输入数据第一行是同学的数量N 和特产的数量M。
第二行包含M 个整数,表示每一种特产的数量。
N, M 不超过1000,每一种特产的数量不超过1000
Output
输出一行,不同分配方案的总数。由于输出结果可能非常巨大,你只需要输出最终结果
MOD 1,000,000,007 的数值就可以了。
Sample Input
5 4 1 3 3 5
Sample Output
384835
题解:
首先我们要知道一个结论,把m相同的物品分给n个人的方案数是C(m+n-1,n-1),这个我们可以随便画上去m+n—1个求,其中选n-1个球,把整个序列划分成了n段,每一段就是每个盒子了球的个数,这样就简单证明了这个结论。
然后,我们就可以统计出所有的方案数——∏(1~m)C(ai+n-1)(n-1)(ai是i号特产的数量)。得到这个我们也可以推出式子C(n,f)*∏(1~m)C(ai+n-f-1)(n-f-1)表示我们强制不选f个人,让他们一个都没有,也就是至少f个人一个都没有的方案数,记为f[i]。
那么根据容斥,ans=f[0]-f[1]+f[2]-f[3]……,这样就统计出答案了。
代码:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> #define MAXN 2100 #define mod 1000000007 #define ll long long using namespace std; ll c[MAXN][MAXN],a[MAXN]; ll ans=0;int n,m; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%lld",&a[i]); c[1][0]=c[1][1]=1; for(int i=2;i<=2000;i++){ c[i][0]=1; for(int j=1;j<=i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod; } for(int i=0,f=1;i<=n;i++,f=-f){ int now=c[n][i]; for(int j=1;j<=m;j++) now=(now*c[a[j]+n-i-1][n-i-1])%mod; ans=(ans+now*f)%mod; } printf("%lld",(ans+mod)%mod); return 0; }