序列 a 的普通生成函数(ordinary generating function,OGF)定义为形式幂级数:
F(x)=n∑anxn
a 既可以是有穷序列,也可以是无穷序列。常见的例子(假设 a 以 0 为起点):
- 序列 a=⟨1,2,3⟩ 的普通生成函数是 1+2x+3x2。
- 序列 a=⟨1,1,1,⋯⟩ 的普通生成函数是 ∑n≥0xn。
- 序列 a=⟨1,2,4,8,16,⋯⟩ 的生成函数是 ∑n≥02nxn。
- 序列 a=⟨1,3,5,7,9,⋯⟩ 的生成函数是 ∑n≥0(2n+1)xn。
换句话说,如果序列 a 有通项公式,那么它的普通生成函数的系数就是通项公式。
基本运算
考虑两个序列 a,b 的普通生成函数,分别为 F(x),G(x)。那么有
F(x)±G(x)=n∑(an±bn)xn
因此 F(x)±G(x) 是序列 ⟨an±bn⟩ 的普通生成函数。
考虑乘法运算,也就是卷积:
F(x)G(x)=n∑xni=0∑naibn−i
因此 F(x)G(x) 是序列 ⟨∑i=0naibn−i⟩ 的普通生成函数。
封闭形式
在运用生成函数的过程中,我们不会一直使用形式幂级数的形式,而会适时地转化为封闭形式以更好地化简。
例如 ⟨1,1,1,⋯⟩ 的普通生成函数 F(x)=∑n≥0xn,我们可以发现
F(x)x+1=F(x)
那么解这个方程得到
F(x)=1−x1
这就是 ∑n≥0xn 的封闭形式。
考虑等比数列 ⟨1,p,p2,p3,p4,⋯⟩ 的生成函数 F(x)=∑n≥0pnxn,有
F(x)px+1F(x)=F(x)=1−px1
等比数列的封闭形式与展开形式是常用的变换手段。
请求出下列数列的普通生成函数(形式幂级数形式和封闭形式)。难度是循序渐进的。
- a=⟨0,1,1,1,1,⋯⟩。
- a=⟨1,0,1,0,1,⋯⟩。
- a=⟨1,2,3,4,⋯⟩。
- an=(nm)(m 是常数,n≥0)。
- an=(nm+n)(m 是常数,n≥0)。
第一个:
F(x)=n≥1∑xn=1−xx
第二个:
F(x)=n≥0∑x2n=n≥0∑(x2)n=1−x21
第三个(求导):
F(x)=n≥0∑(n+1)xn=n≥1∑nxn−1=n≥0∑(xn)′=(1−x1)′=(1−x)21
第四个(二项式定理):
F(x)=n≥0∑(nm)xn=(1+x)m
第五个:
F(x)=n≥0∑(nm+n)xn=(1−x)m+11
可以使用归纳法证明。
首先当 m=0 时,有 F(x)=1−x1。
而当 m>0 时,有
(1−x)m+11=(1−x)m11−x1=(n≥0∑(nm+n−1)xn)(n≥0∑xn)=n≥0∑xni=0∑n(im+i−1)=n≥0∑(nm+n)xn
斐波那契数列的生成函数
接下来我们来推导斐波那契数列的生成函数。
斐波那契数列定义为 a0=0,a1=1,an=an−1+an−2(n>1)。设它的普通生成函数是 F(x),那么根据它的递推式,我们可以类似地列出关于 F(x) 的方程:
F(x)=xF(x)+x2F(x)−a0x+a1x+a0
那么解得
F(x)=1−x−x2x
那么接下来的问题是,如何求出它的展开形式?
展开方式一
不妨将 x+x2 当作一个整体,那么可以得到
F(x)=1−(x+x2)x=xk=0∑∞(x+x2)k=xk=0∑∞i=0∑k(ik)xk−i(x2)i=k=0∑∞i=0∑k(ik)xk+i+1=n=1∑∞i=0∑⌊(n−1)/2⌋(in−i−1)xn.
最后一步中,令 n=k+i+1 并更换求和顺序。由此,可以得到通项公式:
an=i=0∑⌊(n−1)/2⌋(in−i−1).
这并不是我们熟知的有关黄金分割比的形式。
展开方式二
考虑求解一个待定系数的方程:
1−axA+1−bxB=1−x−x2x
通分得到
(1−ax)(1−bx)A−Abx+B−aBx=1−x−x2x
待定项系数相等,我们得到
⎩⎨⎧A+B=0−Ab−aB=1a+b=1ab=−1
解得
⎩⎨⎧A=51B=−51a=21+5b=21−5
那么我们根据等比数列的展开式,就可以得到斐波那契数列的通项公式:
1−x−x2x=n≥0∑xn51((21+5)n−(21−5)n)
这也被称为斐波那契数列的另一个封闭形式(1−x−x2x 是一个封闭形式)。
对于任意多项式 P(x),Q(x),生成函数 Q(x)P(x) 的展开式都可以使用上述方法求出。在实际运用的过程中,我们往往先求出 Q(x) 的根,把分母表示为 ∏(1−pix)di 的形式,然后再求分子。
当对分母进行因式分解但有重根时,每有一个重根就要多一个分式,如考虑生成函数
G(x)=(1−x)(1−2x)21
的系数的通项公式,那么有
G(x)=1−xc0+1−2xc1+(1−2x)2c2
解得
⎩⎨⎧c0c1c2=1=−2=2
那么
[xn]G(x)=1−2n+1+(n+1)⋅2n+1
牛顿二项式定理
我们重新定义组合数的运算:
(kr)=k!rk(r∈C,k∈N)
注意 r 的范围是复数域。在这种情况下。对于 α∈C,有
(1+x)α=n≥0∑(nα)xn
二项式定理其实是牛顿二项式定理的一个特殊情况。
卡特兰数的生成函数
参考 Catalan 数形式的代数推演。
应用
接下来给出一些例题,来介绍生成函数在 OI 中的具体应用。
食物
在许多不同种类的食物中选出 n 个,每种食物的限制如下:
- 承德汉堡:偶数个
- 可乐:0 个或 1 个
- 鸡腿:0 个,1 个或 2 个
- 蜜桃多:奇数个
- 鸡块:4 的倍数个
- 包子:0 个,1 个,2 个或 3 个
- 土豆片炒肉:不超过一个。
- 面包:3 的倍数个
每种食物都是以「个」为单位,只要总数加起来是 n 就算一种方案。对于给出的 n 你需要计算出方案数,对 10007 取模。
这是一道经典的生成函数题。对于一种食物,我们可以设 an 表示这种食物选 n 个的方案数,并求出它的生成函数。而两种食物一共选 n 个的方案数的生成函数,就是它们生成函数的卷积。多种食物选 n 个的方案数的生成函数也是它们生成函数的卷积。
在理解了方案数可以用卷积表示以后,我们就可以构造生成函数(标号对应题目中食物的标号):
- n≥0∑x2n=1−x21。
- 1+x。
- 1+x+x2=1−x1−x3。
- 1−x2x。
- n≥0∑x4n=1−x41。
- 1+x+x2+x3=1−x1−x4。
- 1+x。
- 1−x31。
那么全部乘起来,得到答案的生成函数:
F(x)=(1−x2)(1−x)(1−x2)(1−x4)(1−x)(1−x3)(1+x)(1−x3)x(1−x4)(1+x)=(1−x)4x
然后将它转化为展开形式(使用封闭形式练习中第五个练习):
F(x)=n≥1∑(n−1n+2)xn
因此答案就是 (n−1n+2)=(3n+2)。
Sweet
有 n 堆糖果。不同的堆里糖果的种类不同(即同一个堆里的糖果种类是相同的,不同的堆里的糖果的种类是不同的)。第 i 个堆里有 mi 个糖果。现在要吃掉至少 a 个糖果,但不超过 b 个。求有多少种方案。
两种方案不同当且仅当吃的个数不同,或者吃的糖果中,某一种糖果的个数在两个方案中不同。
n≤10,0≤a≤b≤107,mi≤106。
在第 i 堆吃 j 个糖果的方案数(显然为 1)的生成函数为
Fi(x)=j=0∑mixj=1−x1−xmi+1
因此总共吃 i 个糖果的方案数的生成函数就是
G(x)=i=1∏nFi(x)=(1−x)−ni=1∏n(1−xmi+1)
现在我们要求的是 ∑i=ab[xi]G(x)。
由于 n≤10,因此我们可以暴力展开 ∏i=1n(1−xmi+1)(最多只有 2n 项)。
然后对 (1−x)−n 使用牛顿二项式定理:
(1−x)−n=i≥0∑(i−n)(−x)i=i≥0∑(in−1+i)xi
我们枚举 ∏i=1n(1−xmi+1) 中 xk 项的系数,假设为 ck。那么它和 (1−x)−n 相乘后,对答案的贡献就是
cki=a−k∑b−k(in−1+i)=ck((b−kn+b−k)−(a−k−1n+a−k−1))
这样就可以 O(b) 地求出答案了。
时间复杂度 O(2n+b)。