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 //It is made by Awson on 2017.9.25 2 #include <set> 3 #include <map> 4 #include <cmath> 5 #include <ctime> 6 #include <queue> 7 #include <stack> 8 #include <string> 9 #include <cstdio> 10 #include <vector> 11 #include <cstdlib> 12 #include <cstring> 13 #include <iostream> 14 #include <algorithm> 15 #define Min(a, b) ((a) < (b) ? (a) : (b)) 16 #define Max(a, b) ((a) > (b) ? (a) : (b)) 17 #define LL long long 18 using namespace std; 19 const int N = 1000; 20 const int MOD = 1000000007; 21 22 int n, m, mx; 23 int a[N+5]; 24 int C[N*2+5][N*2+5]; 25 26 void work() { 27 scanf("%d%d", &n, &m); 28 for (int i = 1; i <= m; i++) { 29 scanf("%d", &a[i]); 30 mx = Max(mx, a[i]); 31 } 32 mx += n; 33 for (int i = 0; i <= mx; i++) { 34 C[i][0] = 1; 35 for (int j = 1; j <= i; j++) 36 C[i][j] = (C[i-1][j-1]+C[i-1][j])%MOD; 37 } 38 LL ans = 0; 39 for (int i = 0; i < n; i++) { 40 LL cnt = 1; 41 for (int j = 1; j <= m; j++) 42 cnt = cnt*C[a[j]+n-1-i][n-1-i]%MOD; 43 cnt = cnt*C[n][i]%MOD; 44 if (i%2) ans = (ans+MOD-cnt)%MOD; 45 else ans = (ans+cnt)%MOD; 46 } 47 printf("%lld ", ans); 48 } 49 int main() { 50 work(); 51 return 0; 52 }