题解 P5505 【[JSOI2011]分特产】
容斥原理
解决方案
看了一下这道题的题解,我觉得没有人阐释清楚在容斥的时候为什么会出现一加一减的情况,所以自己附上一篇题解
我们设
接下来我们考虑如何求解g[0]
设
求解f数组
我们可以根据
然后我们分别处理每个特产分出去的方案数,最后的乘积就是答案。然后由于强制哪个同学也不确定,而规定
所以,综上所述
解释一下减去i的原因,
为什么最后的答案为ans=\sum_{i=0}^{n-1} (-1)^if[i]
其实我们可以发现,例如计算至少有一个人没有分到的方案数时,假设我们在规定
我们可以发现,通过上述的
即为我们的答案,附上AC代码
code
#include <bits/stdc++.h>
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
const int N=2010,MOD=1000000007;
typedef long long ll;
int n,m;
ll ans,a[N],c[N][N];
inline void intial() //初始化组合数
{
c[0][0]=1;
for(int i=1;i<=N-5;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;
}
}
int main()
{
intial();
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%lld",&a[i]);
//设数组g[i]表示 刚好 有i个同学没有土特产,显然g[0]就是答案
//设f[i]表示 至少 有i个同学没有土特产,通过计算发现每个f[i]可能会重复计算g[i],以样例为例
//f[0]=g[0]+g[1]+g[2]+g[3]+g[4]
//f[1]=g[1]+g[2]*2+g[3]*3+g[4]*4
//f[2]=g[2]+g[3]*3+g[4]*6
//f[3]=g[3]+g[4]*4
//f[4]=g[4]
//根据容斥原理得到公式:
//ans=f[0] -f[1]+f[2]-f[3]+...+(-1)(n次方)f[n]
for(int i=0;i<n;i++){ //强制任一i个同学没有特产,那么有c[n][i]种方法
ll res=c[n][i]; //隔板法,再通过可重复组合计算易得:
for(int j=1;j<=m;j++) //m个东西随意分给n个人方案数为c[m+n-1][n-i-1],一共的方案数就要把这些土特产的方案数全部乘起来
res=res*c[a[j]+n-i-1][n-i-1]%MOD;
if(i&1) ans=(ans-res+MOD)%MOD; //求得f[i]后根据ans公式即可求解
else ans=(ans+res+MOD)%MOD;
}
printf("%d\n",ans);
return 0;
}