【BZOJ 4710】 4710: [Jsoi2011]分特产 (容斥原理)
4710: [Jsoi2011]分特产
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 99 Solved: 65Description
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,每一种特产的数量不超过1000Output
输出一行,不同分配方案的总数。由于输出结果可能非常巨大,你只需要输出最终结果MOD 1,000,000,007 的数值就可以了。Sample Input
5 4
1 3 3 5Sample Output
384835HINT
Source
【分析】
做这种题要容斥原理和组合数学都好才可以啊
假设只有一种,那么就是把n个球分到m个集合里面,要非空,就是C[N-1][M-1]
但是有多种,每种分别讨论的话是不能保证非空的,合起来讨论的话最后也不能除以x!【我一开始就这样错
所以要用容斥,
答案=总-至少一个空+至少两个空-至少三个空。。。
然后子问题变成n个球分到m个集合里,可以空,就是C[n+m-1][n-1]。因为是“至少”。
乘起来容斥即可。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Maxn 1100 8 #define Mod 1000000007 9 #define LL long long 10 11 int w[Maxn],c[2*Maxn][2*Maxn]; 12 13 void init(int n) 14 { 15 for(int i=0;i<=2000;i++) c[i][0]=1; 16 for(int i=1;i<=2000;i++) 17 for(int j=1;j<=i;j++) 18 c[i][j]=(c[i-1][j]+c[i-1][j-1])%Mod; 19 } 20 21 int main() 22 { 23 int n,m; 24 scanf("%d%d",&n,&m); 25 init(n); 26 int ans=0; 27 for(int i=1;i<=m;i++) 28 { 29 scanf("%d",&w[i]); 30 } 31 for(int i=0;i<n;i++) 32 { 33 int nw=1,ii=n-i; 34 for(int j=1;j<=m;j++) 35 { 36 nw=1LL*nw*c[w[j]+ii-1][ii-1]%Mod; 37 } 38 if(i&1) ans=(ans-1LL*c[n][i]*nw%Mod)%Mod; 39 else ans=(ans+1LL*c[n][i]*nw)%Mod; 40 } 41 ans=(ans+Mod)%Mod; 42 printf("%d\n",ans); 43 return 0; 44 }
2017-04-19 21:23:51