[JSOI2011] 分特产
题目描述
JYY 带队参加了若干场 ACM/ICPC \text{ACM/ICPC} ACM/ICPC 比赛,带回了许多土特产,要分给实验室的同学们。
JYY 想知道,把这些特产分给 n n n 个同学,一共有多少种不同的分法?当然,JYY 不希望任何一个同学因为没有拿到特产而感到失落,所以每个同学都必须至少分得一个特产。
例如,JYY 带来了
2
2
2 袋麻花和
1
1
1 袋包子,分给
A
A
A 和
B
B
B 两位同学,那么共有
4
4
4 种不同的
分配方法:
A A A:麻花, B B B:麻花、包子
A A A:麻花、麻花, B B B:包子
A A A:包子, B B B:麻花、麻花
A A A:麻花、包子, B B B:麻花
输入格式
输入数据:
第一行是同学的数量 n n n 和特产的数量 m m m。
第二行包含 m m m 个整数,表示每一种特产的数量。
n , m n, m n,m 不超过 1000 1000 1000 ,每一种特产的数量不超过 1000 1000 1000。
输出格式
输出一行,不同分配方案的总数。
由于输出结果可能非常巨大,你只需要输出最终结果
m
o
d
1
0
9
+
7
\bmod\ {10^9+7}
mod 109+7 的数值就可以了。
样例 #1
样例输入 #1
5 4
1 3 3 5
样例输出 #1
384835
思路
- 很明显的隔板法。
- 但关键是隔板法是针对于小球相同的,但本道题只有同一个种类的小球才相同。(此时我们是把同学看成盒子(也就是板),把特产看成小球)。
- 此时直接想,是真的好麻烦。
- 因此我们考虑容斥原理。
- 但本道题不好处理的就是它到底空多少个盒子:可参考
其实,按照图片的意思,也就是说我们正的做很麻烦,我们就反向做。为什么正的很麻烦?因为题目中的盒子(同学不为空)并且考虑到直接计算不为空的合法的太麻烦了,于是先计算所有合法方案,再减去有空缺的答案,就是我们问题的答案了。然后空缺的答案的计算过程就为图中所写的。
拓展:容斥原理在计算的时候往往是奇数时正好,偶数时负号。
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
const int N = 2010,mod = 1e9+7;
int c[N][N];
int f[N];
int w[N];
int n,m;
void init(){
for(int i=0;i<=2000;i++){
for(int j=0;j<=i;j++){
if(!j)c[i][j]=1;
else{
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
}
}
}
signed main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>w[i];
}
init();
for(int i=0;i<n;i++){
f[i]=1;
for(int j=1;j<=m;j++){
f[i]=f[i]*c[w[j]+n-1-i][n-1-i]%mod;
}
}
int t=1;
int res=0;
for(int i=0;i<n;i++){
t=(i&1)?-1:1;
res=((res+f[i]*t*c[n][i]%mod)%mod+mod)%mod;
}
cout<<res;
return 0;
}