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
Sample Output
384835
首先,如果没有“每个人至少拿一个”的限制,那么答案就用经典的插板法解决。。
然后我们肯定要容斥一下。还是老套路,我们要-{至少有一个人没有特产的方案}+{至少有两个人没有特产的方案}-{至少有三个人没有特产的方案}...
考虑求至少k个人没拿到特产的方案。首先我们要枚举哪k个人没拿到特产,然后再将所有特产分给剩下的n-k个人。所以方案数就是。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<ctime>
#define ll long long
#define mod 1000000007ll
using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
int n,m;
int w[1005];
ll f[1005],g[1005];
ll c[2005][2005],s,ans,tot[1005];
int main() {
n=Get(),m=Get();
c[0][0]=1;
for(int i=1;i<=2000;i++)
for(int j=0;j<=i;j++)
c[i][j]=(!j||i==j)?1:(c[i-1][j-1]+c[i-1][j])%mod;
for(int i=1;i<=m;i++) w[i]=Get();
for(int i=1;i<=n;i++) {
tot[i]=1;
for(int j=1;j<=m;j++) {
tot[i]=tot[i]*c[w[j]+i-1][i-1]%mod;
}
}
int flag=1;
for(int i=n;i>=1;i--) {
ans=(ans+flag*c[n][i]*tot[i]%mod+mod)%mod;
flag*=-1;
}
cout<<ans;
return 0;
}