牛客生成函数I

简单学了点生成函数。核心在于把多项式的指数看作个数,则多项式系数就是对应个数的方案数。

A. 背包

题意:

有8种物品,每种物品选取个数限制如下:

  • 肥宅快乐水:最多1个(0或1)
  • 鸡腿:最多1个(0或1)
  • 鸡翅:必须偶数个(0,2,4,...)
  • 鸡块:必须4的倍数个(0,4,8,...)
  • 鸡汤:必须奇数个(1,3,5,...),不能为0
  • 鸡蛋:必须3的倍数个(0,3,6,...)
  • 大盘鸡:最多2个(0,1,2)
  • 啤酒鸡:最多3个(0,1,2,3)

求选取总数为 \(N\) 个物品的方案数,对 \(10^9+7\) 取模。\(N \le 10^{18}\)

思路:

写出每种物品的生成函数并相乘:

  • 肥宅快乐水:\(1+x\)
  • 鸡腿:\(1+x\)
  • 鸡翅:\(1+x^2+x^4+\cdots = \frac{1}{1-x^2}\)
  • 鸡块:\(1+x^4+x^8+\cdots =\frac{1}{1-x^4}\)
  • 鸡汤:\(x+x^3+x^5+\cdots = \frac{x}{1-x^2}\)
  • 鸡蛋:\(1+x^3+x^6+\cdots =\frac{1}{1-x^3}\)
  • 大盘鸡:\(1+x+x^2 = \frac{1-x^3}{1-x}\)
  • 啤酒鸡:\(1+x+x^2+x^3 = \frac{1-x^4}{1-x}\)

总生成函数:

\[A(x)=(1+x)^2\cdot\frac{1}{1-x^2}\cdot\frac{1}{1-x^4}\cdot\frac{x}{1-x^2}\cdot\frac{1}{1-x^3}\cdot\frac{1-x^3}{1-x}\cdot\frac{1-x^4}{1-x} \]

约去 \((1-x^3)\)\((1-x^4)\),并利用 \(1-x^2=(1-x)(1+x)\) 化简:

\[A(x)=\frac{x(1+x)^2}{(1-x)^2(1-x^2)^2}=\frac{x(1+x)^2}{(1-x)^2(1-x)^2(1+x)^2}=\frac{x}{(1-x)^4} \]

\(\displaystyle\frac{1}{(1-x)^4}=\sum_{n\ge 0}\binom{n+3}{3}x^n\),乘以 \(x\)\(x^N\) 系数为 \(\binom{N+2}{3}\)

所以答案为 \(\displaystyle \frac{N(N+1)(N+2)}{6} \bmod (10^9+7)\)。使用快速幂求6的逆元即可。

代码

点击查看代码
void solve() {
	init();
	int n,m;
	cin>>n;
	n--;
	cout<<(n+3)%mod*((n+2)%mod)%mod*((n+1)%mod)%mod*qpow(6,mod-2)%mod<<endl;
}

B. Devu and Flowers

题意:

给定 \(n\) 个盒子,第 \(i\) 个盒子中有 \(f_i\) 朵同色花,不同盒子颜色互不相同。求选出恰好 \(s\) 朵花的方案数(同一盒子内选出的花数量不同即视为不同方案),答案对 \(10^9+7\) 取模。\(n\le 20\)\(s\le 10^{14}\)\(f_i\le 10^{12}\)

思路:

把生成函数相乘:\(\displaystyle\prod_{i=1}^{n}\frac{1-x^{f_i+1}}{1-x}=\displaystyle\frac{1}{(1-x)^n}\prod_{i=1}^{n}(1-x^{f_i+1})\)
容斥,\(\displaystyle\prod_{i=1}^{n}(1-x^{f_i+1})=\sum_{S\subseteq\{1,2,...,n\}}(-1)^{|S|}x^{\sum_{i\in S}(f_i+1)}\)
\(\displaystyle\frac{1}{(1-x)^n}=\sum_{i=0}^{\infty}\binom{i+n-1}{n-1}x^i\)
\(\displaystyle\prod_{i=1}^{n}(1-x^{f_i+1})=\sum_{i=0}^{\infty}A_ix^i\)\(\displaystyle\frac{1}{(1-x)^n}=\sum_{i=0}^{\infty}B_ix^i\).
两式子相乘,\((\displaystyle\sum_{i=0}^{\infty}A_ix^i)(\sum_{i=0}^{\infty}B_ix^i)=\sum_{N=0}^{\infty}(\sum_{i+j=N}A_iB_j)x^N\)
\(\displaystyle\sum_{i+j=N}A_iB_j=\sum_{S\subseteq\{1,2,...,n\}}(-1)^{|S|}B_{N-\sum_{i\in S}(f_i+1)}=\sum_{S\subseteq\{1,2,...,n\}}(-1)^{|S|}\binom{N-\sum_{i\in S}(f_i+1)+n-1}{n-1}\)
最后枚举集合S计数即可。

代码

点击查看代码
int C(int n,int m){
	int ans=1;
	for(int i=0;i<m;i++){
		ans*=(n-i)%mod;
		ans%=mod;
	}
	ans*=inv[m];
	ans%=mod;
	return ans;
}


int b[N];
int a[N],s[N],S[N];
void solve() {
	init();
	int n,s;
	cin>>n>>s;
	for(int i=0;i<n;i++){
		cin>>a[i];
		a[i]++;
	}
	int ans=0;
	for(int i=0;i<(1ll<<n);i++){
		int sum=0;
		int len=0;
		for(int j=0;j<n;j++){
			if(i>>j&1){
				len++;
				sum+=a[j];
			}
		}
		if(sum<=s){
			if(len%2){
				ans+=mod-C(s-sum+n-1,n-1);
			}else{
				ans+=C(s-sum+n-1,n-1);
			}
			ans%=mod;
		}
	}
	cout<<ans<<endl;
}

Sweets

题意

\(n\) 种糖果,第 \(i\) 种糖果有 \(m_i\) 颗。John 要吃掉总数在 \([a,b]\) 之间的糖果,每种糖果选的数量不能超过 \(m_i\)。求有多少种不同的选择方案,答案模 \(2004\)

思路

与上题一样,先求出生成函数,过程略去:
\(\displaystyle\sum_{N=0}^{\infty}(\sum_{S\subseteq\{1,2,...,n\}}(-1)^{|S|}\binom{N-\sum_{i\in S}(m_i+1)+n-1}{n-1})x^N\)
我们需要求该生成函数的多项式系数的区间和,可以等价成前缀和。将生成函数再乘一个\(\displaystyle\sum_{N=0}^{\infty}x^N\)即可得到多项式系数的前缀和。
一种简单的方法是直接从生成函数的形式看:\(\displaystyle\frac{1}{(1-x)^{n+1}}\prod_{i=1}^{n}(1-x^{f_i+1})\),与原生成函数的区别只有\((1-x)\)的指数不同,直接把式子中组合数的\(n\)替换成\(n+1\)即可。
另一种方法需要运用朱世杰恒等式:
\((\displaystyle\sum_{N=0}^{\infty}(\sum_{S\subseteq\{1,2,...,n\}}(-1)^{|S|}\binom{N-\sum_{i\in S}(m_i+1)+n-1}{n-1})x^N)(\displaystyle\sum_{N=0}^{\infty}x^N)\)
\(=\displaystyle\sum_{N=0}^{\infty}(\sum_{x+y=N}(1\cdot\sum_{S\subseteq\{1,2,...,n\}}(-1)^{|S|}\binom{x-\sum_{i\in S}(m_i+1)+n-1}{n-1}))x^N\)
\(=\displaystyle\sum_{N=0}^{\infty}(\sum_{x=0}^N(1\cdot\sum_{S\subseteq\{1,2,...,n\}}(-1)^{|S|}\binom{x-\sum_{i\in S}(m_i+1)+n-1}{n-1}))x^N\)
\(=\displaystyle\sum_{N=0}^{\infty}((1\cdot\sum_{S\subseteq\{1,2,...,n\}}(-1)^{|S|}(\sum_{x=0}^N\binom{x-\sum_{i\in S}(m_i+1)+n-1}{n-1})))x^N\)
\(=\displaystyle\sum_{N=0}^{\infty}((1\cdot\sum_{S\subseteq\{1,2,...,n\}}(-1)^{|S|}\binom{x-\sum_{i\in S}(m_i+1)+n}{n}))x^N\)
然后枚举集合S计数即可,注意模数是2004,不能直接用逆元。

代码

点击查看代码
int A[N],B[N];
int C(int n,int m){
	int ans=1;
	for(int i=0;i<m;i++){
		A[i]=(n-i);
		B[i]=i+1;
	}
	for (int i = 0; i < m; ++i) {
		for (int j = 0; j < m && B[i] > 1; ++j) {
			int g = gcd(A[j], B[i]);
			A[j] /= g;
			B[i] /= g;
		}
	}
	for(int i=0;i<m;i++){
		ans*=A[i];
		ans%=mod;
	}
	
	return ans;
}


int b[N];
int a[N],s[N],S[N];
void solve() {
	init();
	int n,x,y;
	cin>>n>>x>>y;
	x--;
	for(int i=0;i<n;i++){
		cin>>a[i];
		a[i]++;
	}
	int ans=0;
	for(int i=0;i<(1ll<<n);i++){
		int sum=0;
		int len=0;
		for(int j=0;j<n;j++){
			if(i>>j&1){
				len++;
				sum+=a[j];
			}
		}
		if(sum<=y){
			if(len%2){
				ans+=mod-C(y-sum+n,n);
			}else{
				ans+=C(y-sum+n,n);
			}
			ans%=mod;
		}
		if(sum<=x){
			if(len%2){
				ans+=C(x-sum+n,n);
			}else{
				ans+=mod-C(x-sum+n,n);
			}
			ans%=mod;
		}
	}
	cout<<ans<<endl;
}

D. Blocks

题意

给定长度为 \(n\) 的序列,有红、黄、蓝、绿四种颜色砖块,每块长度 \(1\)。要求用砖块铺满序列,且红色和绿色砖块的数量均为偶数。求方案数模 \(10007\)\(n \le 10^9\)

思路

我做题时没想到生成函数的做法,直接用组合数求出来的。
不难推理出方案数为:\(\displaystyle\sum_{i=0}^{\lfloor \frac{n}{2}\rfloor}\binom{n}{2i}2^{n-2i}\displaystyle\sum_{j=0}^i\binom{2i}{2j}\)
(要注意i=0时的值另算)
\(=2^n+\displaystyle\sum_{i=1}^{\lfloor \frac{n}{2}\rfloor}\binom{n}{2i}2^{(n-2i)+(2i-1)}\)
\(=2^n+2^{n-1}\displaystyle\sum_{i=1}^{\lfloor \frac{n}{2}\rfloor}\binom{n}{2i}\)
\(=2^n+2^{n-1}(2^{n-1}-1)\)
\(=4^{n-1} + 2^{n-1}\)

然后是生成函数的做法:
\(a_n\) 为满足条件的方案数。考虑指数生成函数:红、绿要求偶数,其 EGF 为 \(\frac{e^x+e^{-x}}{2}\),黄、蓝无限制,EGF 为 \(e^x\)。总的 EGF 为

\[\left(\frac{e^x+e^{-x}}{2}\right)^2 e^{2x} = \frac{e^{4x}+2e^{2x}+1}{4} \]

提取 \(\frac{x^n}{n!}\) 系数,当 \(n \ge 1\) 时得到

\[a_n = \frac{4^n + 2\cdot 2^n}{4} = 4^{n-1} + 2^{n-1} \]

代码

点击查看代码
void solve() {
//	init();
	int n,x,y;
	cin>>n;
	int ans=qpow(2,n)+qpow(2,n-1)*(qpow(2,n-1)-1+mod)%mod;
	ans%=mod;
	cout<<ans<<endl;
	
}

E. Lust

题意:

\(n\) 个数 \(a_1,\dots,a_n\),进行 \(k\) 次操作,每次等概率随机选一个下标 \(x\in[1,n]\),将 \(a_x\)\(1\),同时将答案加上除 \(a_x\) 外所有数的乘积。求最终答案的期望,对 \(10^9+7\) 取模。

思路:

设当前所有数乘积为 \(P\)。一次操作选中 \(x\),增加量为 \(P/a_x\),操作后新的乘积 \(P'=(a_x-1)\cdot \frac{P}{a_x}=P-\frac{P}{a_x}\)。因此每次增加量等于乘积的减少量。\(k\) 次操作的总增加量即为初始乘积与最终乘积的差:\(\prod a_i-\prod(a_i-c_i)\),其中 \(c_i\) 是第 \(i\) 个数被选次数。

然后不会了,期望算不来,下次学了概率论再说。

代码

点击查看代码

posted @ 2026-07-20 20:40  ptlks  阅读(3)  评论(0)    收藏  举报