Devu and Flowers(母函数\生成函数-二进制枚举)(Codeforces Round #258-Div. 2-451E)

文章目录

  • 题目
  • 思路
  • 代码

题目

D e v u Devu Devu 想用花去装饰他的花园,他已经购买了 n n n个箱子,第 i i i个箱子有 f i f_i fi朵花,在同一个的箱子里的所有花是同种颜色的(所以它们没有任何其他特征)。另外,不存在两个箱子中的花是相同颜色的。 现在 D e v u Devu Devu 想从这些箱子里选择 s s s朵花去装饰他的花园, D e v u Devu Devu 想要知道,总共有多少种方式从这些箱子里取出这么多的花?因为结果有可能会很大,结果需要对 1 0 9 + 7 10^9+7 109+7 取模。 D e v u Devu Devu 认为至少有一个箱子中选择的花的数量不同才是两种不同的方案。
输入:
第一行: n , s n,s n,s
第二行: f 1 , f 2 , . . . , f n f_1,f_2,...,f_n f1,f2,...,fn
数据范围: 1 ≤ n ≤ 20 , 0 ≤ s ≤ 1 0 14 , 0 ≤ f i ≤ 1 0 12 1\le n\le20,0\le s\le10^{14},0\le f_i\le10^{12} 1n20,0s1014,0fi1012

思路

我们考虑对于第 i i i 种花的生成函数:
F i ( x ) = 1 + x + x 2 + . . . + x f i = 1 − x f i + 1 1 − x F_i(x)=1+x+x^2+...+x^{f_i}=\frac{1-x^{f_i+1}}{1-x} Fi(x)=1+x+x2+...+xfi=1x1xfi+1
那么考虑总方案数的生成函数:
G ( x ) = ∏ i = 1 n F i ( x ) = ∏ i = 1 n 1 − x f i + 1 1 − x = ∏ i = 1 n ( 1 − x f i + 1 ) ( 1 − x ) n G(x)=\prod_{i=1}^nF_i(x)=\prod_{i=1}^n\frac{1-x^{f_i+1}}{1-x}=\frac{\prod_{i=1}^n(1-x^{f_i+1})}{(1-x)^n} G(x)=i=1nFi(x)=i=1n1x1xfi+1=(1x)ni=1n(1xfi+1)
然后就套路一波,因为:
H ( x ) = 1 + x + x 2 + . . . = 1 1 − x H(x)=1+x+x^2+...=\frac{1}{1-x} H(x)=1+x+x2+...=1x1
所以:
G ( x ) = ( ∏ i = 1 n ( 1 − x f i + 1 ) ) ∗ ( 1 + x + x 2 + . . . ) n G(x)=(\prod_{i=1}^n(1-x^{f_i+1}))*(1+x+x^2+...)^n G(x)=(i=1n(1xfi+1))(1+x+x2+...)n
那我们要求 G ( x ) G(x) G(x) s s s 项的系数 a s a_s as
我们发现右边就是不定方程的非负整数解方案数, g i = C i + n − 1 n g_i=C_{i+n-1}^{n} gi=Ci+n1n
左边由于 n n n 很小,所以考虑二进制枚举
我们记左边枚举所得结果为: c x p cx^p cxp那么右边应为 g s − p g_{s-p} gsp
那么
A n s = ∑ S c x p ∗ g s − p Ans=\sum^Scx^p*g_{s-p} Ans=Scxpgsp
g i g_i gi L u c a s Lucas Lucas定理计算即可

代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
#define ULL unsigned long long
LL read(){
	LL f=1,x=0;char c=getchar();
	while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
	while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return f*x;
}
#define MAXN 20
#define Mod (LL)(1e9+7)
#define INF 0x3f3f3f3f
LL f[MAXN+5];
LL Pow(LL x,LL y){
	LL ret=1;
	while(y){
		if(y&1) ret=ret*x%Mod;
		x=x*x%Mod;
		y>>=1;
	}
	return ret;
}
LL Lucas(LL n,LL m){
	m=min(m,n-m);
	LL ret=1;
	while(n&&m){
		LL a=1,b=1,n0=n%Mod,m0=m%Mod;
		for(LL i=n0;i>=n0-m0+1;i--) a=a*i%Mod;
		for(LL i=1;i<=m0;i++) b=b*i%Mod;
		ret=ret*a%Mod*Pow(b,Mod-2)%Mod;
		n/=Mod,m/=Mod;
	}
	return ret;
}
int main(){
	int n=read();
	LL ans=0,s=read();
	for(int i=1;i<=n;i++)
		f[i]=read();
	for(int S=0;S<(1<<n);S++){
		LL cnt=s,sign=1;
		for(int i=1;i<=n;i++)
			if(S&(1<<(i-1)))
				cnt-=f[i]+1,sign=-sign;
		if(cnt<0) continue;
		ans=(ans+sign*Lucas(n+cnt-1,n-1)%Mod)%Mod;
	}
	printf("%lld\n",(ans+Mod)%Mod);
	return 0;
}

你可能感兴趣的:(构造,生成函数\母函数,CodeForces,数学,二进制,计数,排列组合)