生成函数
生成函数 :
1. 普通生成函数
\((a_n)_{n\in\mathbb{N}}\)的母函数, 也被称作“生成函数(Generating Function)“, 是一种形式幂级数, 其每一项的系数都可以提供关于这个数列的信息.
e.g.
其中第 \(i\) 项的系数是数列的第 \(i\) 项, 而自变量 \(x\) 的选取不改变这个多项式的意义, 故我们称这种函数为形式幂级数. 如上所示的 \(G(x)\) 是一种较常见而直观的母函数, 被称作“普通生成函数(Ordinary Generating Function, OGF)”
1.1 引子
为理解其意义, 我们举两例子:
第一个较简单, 考虑高中时的生物遗传题, 父母基因型均为Aa, 则子代基因型分布为经典的(1:2:1), 老师通常会用如下的方式为学生说明计算逻辑(以及做题时常用的方法):
(这种方法也被称作“配子法”)
如果我们把父母可能产生的配子所携带的基因看作数列的各个项(按出现概率分配出现次数比例), 那么两个配子的结合计算过程就可以看作是两个有限多项式的乘法, 也即:
第二个, 我们考虑一个组合问题:
我们有 \(n\) 种不同的盒子, 每个盒子中有 \(a_i\) 相同的球, 我们取 \(m>n\) 个球(只考虑组合, 不考虑排列), 那么有多少种取出方案?
不难想到通过DP背包的方法解决(不简化双层的原因是为更好说明其与生成函数的关系):
total_balls = 114514 #球的总数
def dp(n, m, A):
DP = [[0] * (m + 1) for _ in range(n + 1)]
#DP[i][j]表示在所需的球选到第i个时,已经判断了j个球的取舍时的方案数
DP[0][0] = 1 #初始情况, 什么都不选的话有1种可能
for i in range(1, n + 1):
for j in range(m + 1):
for k in range(min(A[i - 1], j) + 1):
DP[i][j] += DP[i-1][j-k]
return DP[n][m]
而我们再考虑另一种考虑的视角:
我们有 \(n\) 个数列, 他们对应 \(n\) 个普通生成函数:
我们将这 \(n\) 个多项式相乘,所得到的结果多项式的第 \(m\) 次项系数即为我们所求方案数.
我们思考一下这两种思考角度的异同, 发现背包dp和多项式乘法的过程是相似的, 都是累计结果的相加.
1.2 OGF的基本运算:
我们考虑两生成函数与其对应的两数列:
- 对于两生成函数的和函数, 其对应着两相应数列的和数列\[C(x)=A(x)+B(x)\leftrightarrow [a_n+b_n] \]
- 对于两生成函数的积函数,其对应着两数列的卷积( \(a*b\) )\[A(x)*B(x)\leftrightarrow [c_n=\sum_{i=0}^{n}a_ib_{n-i}] \]
而下面的一种对OGF幂形式的变换卡, 通常能更好的简化运算
1.3 OGF的封闭形式
我们考虑 \(G(x) = \sum^{\infty}_{i=0}x^i\) , 我们发现有:
(仅在 \(x\in[-1,1]\) 时成立, 因为仅有此时 \(x^\infty\)收敛)
故:
(也可由等比公式求和看出)
因为生成函数是形式幂级数, 我们并不考虑 \(x\) 的具体取值.
但是考虑改变对 \(x\) 进行一系列变换, 我们可以获得如下一些数列的生成函数:
1.3.2 OGF的封闭形式的一些变形
- 将 \(x\) 代换成 \(cx\) , 得到\[ G(x)=\frac{1}{1-cx},\leftrightarrow\{1, c, c^2, c^3,...\} \]
- 将 \(x\) 代换成 \(x^c\) , 得到\[ G(x)=\frac{1}{1-x^c},\leftrightarrow\{1, \overbrace{0,..., 0}^{c-1个}, 1, \overbrace{0,..., 0}^{c-1个}, 1,...\} \]
- 分子乘 \(c\)\[ G(x) = \frac{c}{1-x},\leftrightarrow\{c, c, c,...\} \]
- 分子乘 \(x^c\)\[G(x) = \frac{x^c}{1-x},\leftrightarrow\{\overbrace{0,0,...0}^{c个},1,1,1\} \]
- 对原式求 \(n\) 阶导:\[G'(x)=\frac{1}{(1-x)^(n+1)},\leftrightarrow\{a_k=\binom{k-1}{n-k-1}\} \]
PS.若是1阶导, 则得到 \(\{1,2,3,4,...\}\) 的生成函数.
我们这里给出一个通过生成函数解决实际问题的例子:
1.4 引子-斐波那契数列的封闭形式
也即:求解斐波那契数列(Fibonacci Sequence):
我们设:
其中, 每项系数均为相应的Fibonacci项.
那么我们发现:
显然, 我们能发现:
故有:
这个生成函数的多项式形式我们很难直接想到, 但是不难想到将该二次分式变成多个一次式的相加, 注意到:
这两个一次多项式均可以转化成两个数列的生成函数
也即, Fibonacci可被写成两个数列的和, 即
其中:
因此, 我们引出一般地将多项式的比化成幂级数形式:
根据代数基本定理, 对任意的多项式 \(P(x),Q(x)\) ,分式 \(\frac{P(x)}{Q(x)}\) 都可以简化成上述我们熟知的生成函数, 也即:
1.5 牛顿二项式定理
我们定义广义组合数:
那么广义的牛顿二项式定理是:
带入 \(\alpha=-1\) 即得OGF的封闭形式与幂级数形式的转换
我们给出一个更有趣的例子:
1.6 例题:
在许多不同种类的食物中选出 n 个,每种食物的限制如下:
承德汉堡:偶数个
可乐:\(0\) 个或 \(1\) 个
鸡腿:\(0\) 个,\(1\) 个或 \(2\) 个
蜜桃多:奇数个
鸡块:\(4\) 的倍数个
包子:\(0\) 个,\(1\) 个,\(2\) 个或 \(3\) 个
土豆片炒肉:不超过一个。
面包:\(3\) 的倍数个
每种食物都是以「个」为单位,只要总数加起来是 \(n\) 就算一种方案

接下来, 我们介绍指数生成函数.
2. 指数生成函数
序列 \(a\) 的指数生成函数 (exponential generating function,EGF) 定义为形式幂级数
2.1 基本运算:
我们考虑两生成函数与其对应的两数列:
- 对于两指数生成函数的和函数, 其对应着两相应数列的和数列\[C(x)=\hat{A}(x)+\hat{B}(x)\leftrightarrow [a_n+b_n] \]
- 对于两指数生成函数的积函数\[\begin{aligned} \hat{C}(x) &=\hat{A}(x)\cdot \hat{B}(x)\\ &=\sum_ia_i\frac{x^i}{i!}\cdot \sum_ib_i\frac{x^i}{i!}\\ &=\sum_i\sum_{j=0}^{i}(\frac{a_j}{j!}\cdot\frac{b_{i-j}}{(i-j)!})x^i\\ &=\sum_i\frac{x^i}{i!}\sum_{j=0}^{i}\binom{i}{j}a_j\cdot b_{i-j}\\ &\leftrightarrow [c_n=\sum_{k=0}^{n}\binom{n}{j}a_k\cdot b_{n-k}] \end{aligned} \]
2.2 封闭形式
基于 \(e^x\) 在 \(x=0\) 处的泰勒展开, 我们得到:
待我之后学完多项式exp再继续补充
本人学习的时候, 主要参考了:
OI.wiki
算法|小学生都能看懂的生成函数入门教程- 牛客竞赛
浙公网安备 33010602011771号