卧薪尝胆,厚积薄发。
JSOI2011 分特产
Date: Wed Sep 12 21:01:12 CST 2018 In Category: NoCategory

Description:

有 $m$ 种物品,第 $i$ 种有 $c[i]$ 个,把他分给 $n$ 个人,每个人可以分到一些相同的,但不能有人没分到,问本质不同的方案数。
$1\le n,m,c[i] \le 1000$

Solution:

首先如果不考虑不能有人没分到,那么方案数就为 $\begin{align}\prod_{i=1}^mC_{c[i]+n-1}^{n-1}\end{align}$ ,设 $S[i]$ 表示至少有 $i$ 个人没分到的方案数,根据容斥原理有 $ans=S[0]-S[1]+S[2]+\cdots+(-1)^nS[n]$ ,求 $S[i]$ 时先选出 $i$ 个强制他为 $0$ ,剩下的部分可以分到也可以没分到,所以得 $\begin{align}S[k]=C_n^k\prod_{i=1}^mC_{c[i]+(n-k)-1}^{(n-k)-1}\end{align}$ ,最后答案就是 $\begin{align}\sum_{k=0}^n(C_n^k\times(-1)^k\times \prod_{i=1}^mC_{c[i]+(n-k)-1}^{(n-k)-1})\end{align}$ 。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define MOD 1000000007
int n,m;
#define MAXN 2010
int c[MAXN];
typedef long long ll;
ll C[MAXN][MAXN];
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= m;++i)scanf("%d",&c[i]);
C[0][0] = 1;
for(int i = 1;i < MAXN;++i)
{
C[i][0] = 1;
for(int j = 1;j <= i;++j)
{
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
}
}
ll ans = 0;
for(int k = 0;k <= n;++k)
{
ll res = (C[n][k] * ((k & 1) ? -1 : 1) + MOD) % MOD;
for(int i = 1;i <= m;++i)
{
res = res * C[c[i] + (n - k) - 1][(n - k) - 1] % MOD;
}
ans = (ans + res) % MOD;
}
cout << ans << endl;
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡