【二项式反演】洛谷P5505 分特产 题解

今天刚学二项式反演,手感火热!

题目

[JSOI2011] 分特产 - 洛谷

JYY 带队参加了若干场 ACM/ICPC 比赛,带回了许多土特产,要分给实验室的同学们。

JYY 想知道,把这些特产分给 n 个同学,一共有多少种不同的分法?当然,JYY 不希望任何一个同学因为没有拿到特产而感到失落,所以每个同学都必须至少分得一个特产。

例如,JYY 带来了 2 袋麻花和 1 袋包子,分给 A 和 B 两位同学,那么共有 4 种不同的 分配方法:

A:麻花, B:麻花、包子

A:麻花、麻花, B:包子

A:包子, B:麻花、麻花

A:麻花、包子, B:麻花

思路

看一波二项式反演的基本公式:

$g(n)=\sum_{i=0}^{n}\binom{n}{i}f(i)\Leftrightarrow f(n)=\sum_{i=0}^{n}(-1)^{n-i}\binom{n}{i}g(i)$

对于这一题,我们设f(i)表示恰好有i个人没有特产的方案数,发现并不好求!

那么考虑反演,此处使用二项式反演是因为这是统计方案数的一种经典方法:设g(i)为钦定i个人没有特产的方案数

先求f(i),用排列组合里最基本的隔板法:对于f(k),把a_i分给剩下n-k个人,剩下每个人可以分\left [ 0,a_i \right ]个,由此求得可得f(k):

$f(k)=\binom{n}{k}\prod_{i=1}^{m}\binom{a_i+n-k-1}{n-k-1}$

套用二项式反演的公式,可得:

$g(k)=\sum_{i=k}^{n}(-1)^{i-k}\binom{i}{t}f(i)$

 等量代换得:

$g(k)=\sum_{i=k}^{n}(-1)^{i-k}\binom{i}{t}\binom{n}{i}\prod_{i=1}^{m}\binom{a_j+n-i-1}{n-i-1}$

不难发现,答案就是g(0)

$g(0)=\sum_{i=0}^{n}(-1)^i\binom{i}{0}\binom{n}{i}\prod_{i=1}^{m}\binom{a_j+n-i-1}{n-i-1}$

其中$\binom{i}{0}=1$,可以在计算时省去

快乐写代码吧!

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=1e6+9,M=3333,mod=1e9+7;
ll C[M][M];
ll n,m,a[N],f[N],ans,op;
void get()
{
	for(int i=0;i<M;i++)
	C[i][0]=1;
	for(int i=1;i<M;i++)
	for(int j=1;j<=i;j++)
	C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
int main()
{
	get();
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=m;i++)
	scanf("%lld",&a[i]);
	for(int i=0;i<=n;i++)f[i]=C[n][i];
	for(int i=0;i<=n;i++)
	for(int j=1;j<=m;j++)
	f[i]=f[i]*C[a[j]+n-i-1][n-i-1]%mod;
	for(int i=0;i<=n;i++)
	{
		if(i&1)op=-1;
		else op=1;
		ans=(ans+op*f[i])%mod;
	}
	ans=(ans+mod)%mod;
	printf("%lld",ans);
	return 0;
}

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值