[Jsoi2011]分特产
Description
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
1 3 3 5
Sample Output
384835
对于总共n个人,很容易想到第i个物品,分出的方案数为C(n−1,a[i]+n−1),其中a[i]为个数。
但是这样做就会导致有人分不到特产。
考虑容斥,我们-一个人分不到的情况 +两个人分不到的情况 -三个人...
我们直接限定隔板的数目来强制一些人分不到特产,即方案数变为C(n−1−i,a[j]+n−1−i),其中i个人强制分不到,第j个物品。
注意最后,因为分不到的人可以是任意的,所以每次容斥还要*C(i,n)。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 int Mod=1000000007; 7 ll A[10001],ans,B[10001]; 8 int a[10001]; 9 int n,m; 10 ll C(int x,int y) 11 { 12 ll fz=B[y]; 13 ll fm=(A[y-x]*A[x])%Mod; 14 return (fz*fm)%Mod; 15 } 16 int main() 17 {int i,j; 18 cin>>n>>m; 19 for (i=1;i<=m;i++) 20 scanf("%d",&a[i]); 21 A[1]=1;B[1]=1;B[0]=1;A[0]=1; 22 for (i=2;i<=10000;i++) 23 A[i]=((Mod-Mod/i)*A[Mod%i])%Mod,B[i]=(B[i-1]*i)%Mod; 24 for (i=1;i<=10000;i++) 25 A[i]=(A[i]*A[i-1])%Mod; 26 for (i=0;i<n;i++) 27 { 28 ll cnt=1; 29 for (j=1;j<=m;j++) 30 { 31 cnt*=C(n-1-i,a[j]+n-1-i); 32 cnt%=Mod; 33 } 34 cnt=cnt*C(i,n)%Mod; 35 if (i%2==0) ans=(ans+cnt)%Mod; 36 else ans=(ans-cnt+Mod)%Mod; 37 } 38 cout<<ans; 39 }