普通生成函数
定义
对于序列 \(a\) 的的普通生成函数定义为形式幂级数:
\[F(x)=\sum_{n}a_nx^n
\]
运算
显然,两个序列 \(a,b\) 做加减法后的生成函数为:
\[C(x)=A(x)\pm B(x)
\]
而两个序列做卷积也不难发现就是生成函数相乘。
\[A(x)B(x)=\sum_{n}x^n\sum_{i=0}^na_ib_{n-i}
\]
即 \(a*b\) 的生成函数。
封闭形式
假设有生成函数
\[F(x)=\sum_{i=0}^{\infty}x^i
\]
不难发现有
\[\begin{aligned}
&xF(x)+1=F(x)\\
&F(x)=\frac{1}{1-x}
\end{aligned}\]
但是将 \(x=1\) 带进去并不成立?
因为这是封闭形式,不需要带入特定的值。
再比如
\[\begin{aligned}
&G_k(x)=\sum_{i=0}^{\infty}x^{ik}\\
x^kG_k(&x)+1=G_k(x)\\
&G_k(x)=\frac{1}{1-x^k}
\end{aligned}\]
即等比数列的封闭形式。
使用封闭形式会时推导更加简洁。当然,有时也需要将封闭形式展开为形式幂级数。
运用
考虑 dp。设 \(f_i\) 表示和为 \(i\) 的二叉树个数,转移枚举根的权值,再枚举左右两棵子树的权值,可以写成:
\[f_i=\sum_{j\in S}\sum_{k=0}^{i-j}f_{i-j-k}f_{k}
\]
发现 \(j\in S\) 很烦,于是再设一个函数 \(g(x)=[x\in S]\)。
\[f_i=\sum_{j=1}^{i}g_j\sum_{k=0}^{i-j}f_{i-j-k}f_{k}
\]
不难发现就是在对 \(f,g\) 做卷积。而数列的卷积可以转换为生成函数相乘。
设\(f\) 和 \(g\) 的生成函数为 \(F(x),G(x)\)。
\[\begin{aligned}
&F(x)=\sum_{i=0}^{n}f_ix^i\\
&G(x)=\sum_{i=0}^{n}s_ix^i\\
& F(x)=F(x)^2G(x)
\end{aligned}\]
发现不是很对,因为 \(f_0=1\),但是 \(G(x)\) 的 \(g_0=0\),所以需要填上常数项。
\[\begin{aligned}
& F(x)=F(x)^2G(x)+1\\
& F(x)=\frac{1\pm \sqrt{1-4G(x)}}{2G(x)}
\end{aligned}\]
但是 \(2G(x)\) 的常数项为 \(0\),求不了逆。所以将分子的 \(\pm\) 取 \(-\) 号,这样分子常数项也为 \(0\)。提一个 \(x^p\) 出来就可以计算了。
首先,有一个自然的 \(O(n\sqrt n)\) 的做法。
考虑用生成函数怎么做。
对于每一个数 \(k\),单独考虑选了几个 \(k\),可以写出一个生成函数:
\[G_k(x)=\sum_{i=0}^{\infty}x^{ki}=\frac{1}{1-x^k}
\]
而对于答案的生成函数 \(F(x)\),惊奇的发现:
\[F(x)=\prod_{k} G_k(x)=\prod_{k}\frac{1}{1-x^k}
\]
但是 \(\frac{1}{1-x^k}\) 的累乘并不好算。那就转换为加法!
\[\ln F(x)=-\sum_{k}\ln (1-x^k)
\]
那么现在需要求出 \(\ln (1-x^k)\),大力推求导一下:
\[A'(x)=-kx^{k-1}\frac{1}{1-x^k}=-k\sum_{i}x^{ki}x^{k-1}
\]
整理可得:
\[A'(x)=-k\sum_{i}x^{k(i-1)-1}
\]
那么再积分回去:
\[\ln(1-x^k)=-k\int x^{k(i-1)-1} \mathrm{d} x=-k\sum_{i}\frac{x^{k(i-1)}}{k(i-1)}
\]
即:
\[\ln(1-x^k)=-\sum_{i}\frac{x^{ik}}{i}
\]
那么接下来就好办了:
\[\ln F(x)=\sum_{k=1}^{n}\sum_{i=1}^{n}\frac{x^{ik}}{i}
\]
而这个东西显然是调和级数,时间复杂度 \(O(n\log n)\)。最后再 exp 回去就能得到 \(F(x)\)。
错解
与自然数拆分的区别在于多了一个可用的集合和次数限制。
但是相差不大。同样使用生成函数,设第 \(i\) 个物品体积为 \(a_i\),可用 \(b_i\) 次。
发现只需要在上一道题的式子中做一些改动:
\[\ln F(x)=\sum_{k=1}^{n}\sum_{i=1}^{\min(\lfloor \frac{m}{a_k}\rfloor,b_k)}\frac{x^{ia_k}}{i}
\]
然后就做完了吗?发现过不了样例。
正解
问题出在哪里?
发现有了 \(b_i\) 限制后,生成函数并不是无穷项!自然封闭形式也不对!
那么现在在原来的基础上重新改正一下。
\[G_k(x)=\sum_{i=0}^{\min(\lfloor \frac{m}{a_k}\rfloor,b_k)}x^{ia_k}
\]
设 \(\min(\lfloor \frac{m}{a_k}\rfloor,b_k)=lim_k\):
\[\begin{aligned}
&G_k(x)=\sum_{i=0}^{\min(\lfloor \frac{m}{a_k}\rfloor,b_k)}x^{ia_k}=\frac{x^{(lim_k+1)a_k}-1}{x^{a_k}-1}\\
&F(x)=\prod_{k}G_k(x)=\prod_{k}\frac{x^{(lim_k+1)a_k}-1}{x^{a_k}-1}\\
&\ln F(x)=\sum_{k}\ln(\frac{x^{(lim_k+1)a_k}-1}{x^{a_k}-1})=-\sum_{k}\ln(x^{a_k}-1)+\sum_{k}\ln(x^{(lim_k+1)a_k}-1)\\
&\ln F(x)=\sum_{k}\sum_{i}\frac{x^{ia_k}}{i}-\sum_{k}\sum_{i}\frac{x^{i(lim_k+1)a_k}}{i}
\end{aligned}\]
然后就对了。
自然数拆分逆运算?
给定自然数拆分的 \(f_1\sim f_n\) 的方案数,求所用的数的集合 \(S\)。
观察一下自然数拆分得到的式子:
\[\ln F(x)=\sum_{k=1}^{n}\sum_{i=1}^{n}\frac{x^{ik}}{i}
\]
那么现在变成了已知 \(\ln F(x)\),求右边。
而这个过程并不复杂,只需要将 \(i\) 从 \(1\sim n\) 枚举,若 \(f_i>0\)。证明 \(S\) 集合中肯定有 \(i\) 这个元素,同时更新所有 \(f_{ki}\),最终就能得到 \(S\) 集合。
但是,这道题的模数并保证为 NTT 模数,所以需要使用 MTT。(这就是 SDOI)
题目很简单,给定序列 \(a\),求:
\[f_k=\sum_{i=1}^{n}a_i^k
\]
发现不是很好下手,那就直接上生成函数!
\[\begin{aligned}
F(x)&=\sum_{i=0}^{\infty}f_ix^i=\sum_{i=0}^{\infty}\sum_{j=1}^{n}(a_jx)^i=\sum_{j=1}^{n}\sum_{i=0}^{\infty}(a_jx)^i\\
&=\sum_{j=1}^{n}\frac{1}{1-a_jx}
\end{aligned}\]
虽然在自然数拆分中,将 \(\prod\) 转换成了 \(\sum\),但这里的 \(\sum\) 却不好求和。
发现 \(1-a_jx\) 都是一次多项式,如果是 \(\prod\),那么会好计算很多,如何将 \(\sum\) 转换为 \(\prod\) 呢?尝试积分。
\[\int F(x) \mathrm{d}x =\sum_{j=1}^{n}-\frac{1}{a_j}\ln(1-a_jx)
\]
这个 \(a_j\) 很烦,如果没有 \(a_j\),那么就可以将 \(\ln\) 提到外面,里面就是 \(\prod\),可以分治 NTT 。
那想办法让 \(a_j\) 没了就行。不难想到可以对于原式做出一些变换,使得 \(a_j\) 积分后消失。注意到:
\[\begin{aligned}
&F(x)=\sum_{j=1}^{n}\frac{1}{1-a_jx}=\sum_{j=1}^{n}1+\frac{a_jx}{1-a_jx}=n+x\sum_{j=1}^{n}\frac{a_j}{1-a_jx}\\
&\int F(x)\mathrm{d}x=n-x\sum_{j=1}^{n}\ln(1-a_jx)\\
&F(x)=-x\sum_{j=1}^{n}(\ln (1-a_jx))'=-x(\ln(\prod_{j=1}^{n}1-a_jx))'
\end{aligned}\]
分治 NTT,再求 ln 即可。
指数型生成函数
定义
序列 \(a\) 的指数生成函数(exponential generating function,EGF)定义为形式幂级数:
\[\hat{F}(x)=\sum_{n}\frac{a_n}{n!}x^n
\]
注意到指数生成函数同样可以看做 \(\frac{a_i}{i!}\) 的普通生成函数,两者没有本质区别。
运算
两个序列卷积后的指数型生成函数与普通生成函数有所不同:
\[\begin{aligned}
\hat F(x)\hat G(x)&=\sum_{n}\sum_{i=0}^{n}\frac{a_i}{i!}x^i\frac{b_{n-i}}{(n-i)!}x^{n-i}\\
&=\sum_{n}x^n\sum_{i=0}^{n}\frac{a_ib_{n-i}}{i!(n-i)!}=\sum_{n}\frac{x^n}{n!}\sum_{i=0}^{n}\frac{n!a_ib_{n-i}}{i!(n-i)!}\\
&=\sum_n\frac{x^n}{n!}\sum_{i=0}^{n}C_{n}^{i}a_ib_{n-i}
\end{aligned}\]
封闭形式
当 \(a={1,1,1...}\) 时:
\[\hat{F}(x)=\sum_{n}\frac{1}{n!}x^n=e^x
\]
同理,当 \(a\) 为公比为 \(p\) 的等比数列时:
\[\hat{F}(x)=\sum_{n}\frac{1}{n!}x^n=e^{px}
\]
\(\exp \hat F(x)\) 的意义
组合意义
根据封闭形式重新展开:
\[\hat G(x)=\exp \hat{F}(x)=e^{\hat F(x)}=\sum_{n}\frac{\hat F(x)^n}{n!}
\]
赋予其组合意义后就好理解了,设 \(\hat F(x)\) 为 \(n\) 个点的无向连通图的方案数的指数型生成函数。
那么 \(\hat F(x)^n\) 代表的意义就是选取了 \(n\) 个不同的连通图组合起来,构成一个新的图。
而除以 \(n!\) 代表不考虑这些连通块之间的顺序,所以 \(\hat G(x)\) 代表的就是 \(n\) 个点的无向图的方案数的生成函数。
而更加广泛地来说,\(\exp\) 一个指数型生成函数就是将其原来的集合划分为若干个不交的子集的方案数。
OI-wiki 是这样说的:“总结多项式 \(\exp\) 的意义就是:有标号元素构成的集合的生成集族有多少种情况,或划分为任意个非空子集的总方案数。”比较专业,大概也能够理解。
例题
就是上文,求无向连通图的方案数。
注意到其划分为任意集合的方案数就是无向图的方案数,因此设其指数型生成函数为 \(\hat F(x)\),设无向图的方案数的生成函数为 \(\hat G(x)\),那么有:
\[\hat G(x)=\exp \hat F(x)
\]
而左边 \(\hat G(x)\) 是好求的,无向图的方案数只需要考虑每条边选不选:
\[\hat G(x)=\sum_{n}2^{\frac{n\times (n-1)}{2}}\frac{x^n}{n!}
\]
然后就可以算 \(\hat F(x)\) 了:
\[\hat F(x)=\ln \hat G(x)
\]
当然还有另一种推法,只需要会计数和普通生成函数,不过指数型生成函数的做法比较直观,直接使用 \(\exp\) 的组合意义就可以解决。
简化题意,就是有一个 \(n\) 个点的图,\(\frac{n(n-1)}{2}\) 条边,每条边有 \(p\) 的概率存在,问构成的连通块个数的期望。
首先,考虑暴力。不难想到可以枚举连通块大小,然后算构成这么多连通块的概率。设 \(f_i\) 表示构成 \(i\) 个点的无向连通图的概率(只考虑这 \(i\) 个点)。
那么答案可以表示为:
\[(1-p)^{\frac{n(n-1)}{2}}\sum_{i=1}^{n}in!\sum_{k_1+k_2...+k_i=n}\prod_{j=1}^{i}\frac{1}{k_j!}\frac{f_{k_j}}{(1-p)^{\frac{k_j(k_j-1)}{2}}}
\]
其中 \((1-p)\) 部分的概率一开始容易被算掉,但是其实很好理解。因为这 \(i\) 个连通块之间不能有连边,而概率就是上面算的东西。而 \(\frac{n!}{\prod_{j}k_j}\) 是在分配每个连通块的标号。
而这个东西一看就能上指数型生成函数啊。