OGF 学习笔记
生成函数(generating function,简称 GF),一般只应用两种:OGF 和 EGF。
OGF 和 EGF 都是定义在一个数列上的。
【一些前置知识】
二项式卷积:\(c_n=\sum_{i=0}(^n_i)a_ib_{n-i}\)。
\(\exp(A(x))=\sum_{i\ge 0}\dfrac{A(x)^i}{i!}\)。
\(\ln(1-A(x))=-\sum_{i\ge 1}\dfrac{A(x)^i}{i}\)。
\(\exp(\ln(f(x)))=f(x)\)。
复合函数求导:\(f(g(x))\) 的导 \(=f'(g(x))\cdot g'(x)\)。
指数函数的导:\((a^x)'=a^x\ln a\)。
幂函数的导:\((x^a)'=ax^{a-1}\)。
对数函数的导:\(({\log_a}^x)'=\dfrac{1}{x\ln a}\)。特别地,\((\ln x)'=\dfrac{1}{x}\)。
【OGF】
【定义】
对于一个有限序列 \(\{a_i\}(i=0\sim N)\),其 OGF 为 \(f(x)=\displaystyle\sum_{i=0}^Na_i\cdot x^i\)。
对于一个无限序列 \(\{a_i\}\),其 OGF 为 \(f(x)=\displaystyle\sum_{i=0}^{+\infty}a_i\cdot x^i\)。
注意生成函数是一种形式幂级数,也就是一般情况下我们不考虑 \(x\) 具体的值,也不考虑 \(f(x)\) 是否收敛。
(我们把 \(\displaystyle\sum_{i=0}^{+\infty}a_i\cdot x^i\) 的形式称为级数)
注:有时也把 OGF 称作母函数。
砝码称重
有 \(4\) 个砝码,分别为 \(1,2,3,4\) 克。问称出 \(n\) 克的方案数。(砝码只能放在一边)
令 \(G(x)=(1+x^1)(1+x^2)(1+x^3)(1+x^4)\),发现 \(ans=[x^n]G(x)\)。(在一个多项式前加中括号,表示取中括号内的项的系数)
怎么理解呢?\(G(x)\) 每一个括号都代表一个砝码的选择:放或不放。
取球方案
有 \(m\) 种颜色的球,要从里面取出 \(n\) 个球。问方案数。同时有两种情况:
-
每种颜色的球各一个。显然答案是 \((^m_n)\)。
-
每种颜色的球无限个。即求方程 \(x_1+x_2+\dots+x_m=n\) 非负整数解个数,隔板法 \((^{n+m-1}_{m-1})\)。
怎么用生成函数做?
当每种球只有一个,令 \(G(x)=(1+x)^m\),\(ans=[x^n]G(x)\)。显然可以验证,与上面相等。
当每种球有无限个,令 \(G(x)=(1+x+x^2+x^3+\dots)^m=(\dfrac{1}{1-x})^m=\dfrac{1}{(1-x)^m}=(1-x)^{-m}\)。
这里用到广义二项式定理。
可得 \((1-x)^{-m}=\displaystyle\sum_{i=0}^{+\infty}(^{-m}_i)(-x)^i\),则 \(x^n\) 的系数就是 \((-1)^n(^{-m}_n)=(-1)^n\dfrac{(-m)(-m-1)\cdots(-m-n+1)}{n!}\)。
把前面的 \(n\) 个 \(-1\) 挪到分子上面,\(\dfrac{m(m+1)(m+2)\cdots(m+n-1)}{n!}=(^{m+n-1}_n)\),也与上面相等。
装水果
类似这题
要求苹果个数为偶数,香蕉个数为 \(5\) 的倍数,橙子个数为 \(0\sim 4\),梨个数是 \(0\sim 1\)。求拿 \(n\) 个的方案数。
考虑生成函数 \(G(x)=(1+x^2+x^4+\cdots)(1+x^5+x^{10}+\cdots)(1+x+\dots+x^4)(1+x)\)。\(ans=[x^n]G(x)\)
而 \(G(x)=\dfrac{1}{1-x^2}\dfrac{1}{1-x^5}\dfrac{1-x^5}{1-x}(1+x)=\dfrac{1}{(1-x)^2}=(1+x+x^2+\dots)(1+x+x^2+\dots)\)。
观察可得 \([x^n]G(x)=n+1\)。
【运算规则】
记数列 \(\{f\}\) 的生成函数是 \(F(x)\)
-
扩倍规则:若 \(\{f\}\) 每一项乘以 \(C\),则 \(F(x)\leftarrow C\cdot F(x)\)。
-
加法规则:若有另一个数列 \(\{g\}\) 的生成函数是 \(G(x)\),则 \(\{f+g\}\) 的生成函数是 \(F(x)+G(x)\)。
-
右移规则:若让 \(\{f\}\) 开头加上 \(k\) 个 \(0\),则 \(F(x)\leftarrow x^k\cdot F(x)\)。
-
求导规则:\(<f_0,f_1,\dots>\iff F(x)\),则 \(<f_1,2f_2,3f_3,\dots>\iff F'(x)\),这里就是从 \(f_1\) 开始,不是打错了。
练习:求 \(<0^2,1^2,2^2,\dots>\) 的 OGF。
解:\(<1,1,1,1,\dots>\iff \dfrac{1}{1-x}\),则 \(<1,2,3,\dots>\iff \dfrac{1}{(1-x)^2}\)。
注意这里的求导:\((\dfrac{1}{1-x})'\) 属于复合函数求导。
又有 \(<0,1,2,\dots>\iff \dfrac{x}{(1-x)^2}\)。再用一次求导。\(<1^2,2^2,\dots>\iff \dfrac{(1+x)x}{(1-x)^3}\)。
注意这里的求导:\(\dfrac{x}{(1-x)^2}\) 是除法求导,\((\dfrac{A(x)}{B(x)})'=\dfrac{A'(x)B(x)-A(x)B'(x)}{B^2(x)}\)。
- 乘法法则:若有两个数列 \(a,b\) 和生成函数 \(A(x),B(x)\),则生成函数为 \(A(x)B(x)\) 的数列为 \(a,b\) 的卷积。(EGF 对应的是二项式卷积)
【OGF 求递推公式】
汉诺塔问题
\(f_n=2f_{n-1}-1,f_0=0\),求 \(f_n\)。
用归纳法很容易,但是怎么用生成函数做?
考虑 \(f\) 的生成函数 \(F(x)=f_0+f_1x+f_2x^2+\dots\)。
\(f_0=0\),\(f_1x=(2f_0+1)x\),\(f_2x^2=(2f_1+1)x^2\),……,\(f_nx^n=(2f_{n-1}+1)x^n\)。
每个等号左右两边各自加起来,有 \(F(x)=2x\cdot F(x)+x(1+x+x^2+\dots)\)。
所以 \((1-2x)F(x)=\dfrac{x}{1-x}\)。\(F(x)=\dfrac{x}{(1-x)(1-2x)}=\dfrac{1}{1-2x}-\dfrac{1}{1-x}=(1+2x+(2x)^2+\dots)-(1+x+x^2+\dots)\)
观察可以发现 \([x^n]F(x)=2^n-1\)。
斐波那契数列
\(f_n=f_{n-1}+f_{n-2},f_0=0,f_1=1\),求 \(f_n\)。
矩阵快速幂当然可以。但是我们这里还是考虑生成函数 \(F(x)\)。
同样把每个等号左右两边加起来,\(F(x)=xF(x)+x^2F(x)+x\),则 \(F(x)=\dfrac{x}{1-x-x^2}\)。
这里可以因式分解,\(1-x-x^2=(1-\dfrac{1+\sqrt 5}{2}x)(1-\dfrac{1-\sqrt 5}{2}x)\)。刚好可以裂项。令 \(a=\dfrac{1+\sqrt 5}{2},b=\dfrac{1-\sqrt 5}{2}\)。
可得 \(F(x)=\dfrac{\dfrac{1}{\sqrt 5}}{1-ax}-\dfrac{\dfrac{1}{\sqrt 5}}{1-bx}=\displaystyle\sum_{n=0}^{+\infty}\dfrac{1}{\sqrt 5}a^nx^n-\dfrac{1}{\sqrt 5}b^nx^n\)。
所以 \(f_n=\dfrac{a^n-b^n}{\sqrt 5}\)。
卡特兰数
\(f_0=1,f_n=f_0f_{n-1}+\dots+f_{n-1}f_0\)。
(众所周知,\(f_n=\dfrac{C_{2n}^n}{n+1}\))
同样等号两边相加,\(F(x)=1+f_0x\cdot F(x)+f_1x^2F(x)+f_0x^3F(x),F(x)-1=F(x)(f_0x+f_1x^2+\dots)=xF(x)^2\)。
\(xF(x)^2-F(x)+1=0,F(x)=\dfrac{1+\pm\sqrt{1-4x}}{2x}\),那这里是取加号还是减号呢?应该取减号。
为什么不取加号?因为 \(F(x)=\dfrac{1+\sqrt{1-4x}}{2x}\) 在 \(x=0\) 时为 \(\dfrac{1+1}{0}=+\infty\)。而取减号时,\(F(x)\) 在 \(x=0\) 时为 \(\dfrac{0}{0}\),可以用洛必达法则验证其趋向于 \(1\)。
于是 \(F(x)=\dfrac{1-\sqrt{1-4x}}{2x}=\dfrac{1}{2x}-\dfrac{1}{2x}(1-4x)^{\dfrac{1}{2}}\),用广义二项式定理展开。
\(F(x)=\dfrac{1}{2x}-\dfrac{1}{2x}\displaystyle\sum_{i=0}^{+\infty}(^{\frac{1}{2}}_i)(-4x)^i\)。
观察得 \(f_n=[x^n]F(x)=-\dfrac{1}{2}(^{\dfrac{1}{2}}_{n+1})(-4)^{n+1}\),还能进一步简化到 \(\dfrac{(^{2n}_n)}{n+1}\)。
对于一个 \(k\) 次齐次线性递推式:\(f_n+c_1f_{n-1}+\dots+c_kf_{n-k}=0\),\(f_0=d_0,f_1=d_1,\dots,f_{k-1}=d_{k-1}\)。
只要是这种形式,生成函数 \(F(x)\) 可以表示为 \(\dfrac{P(x)}{R(x)}\)。\(P(x)\) 是一个根据 \(c,d\) 推出来的多项式,\(R(x)=1+c_1x+\dots+c_kx^k\)。(\(R(x)\) 是 \(f\) 的特征多项式)
【OGF 的具体应用和 tricks】
例1:整数的 lqp 拆分
题意:定义 \(n\) 的一个 lqp 拆分是把 \(n\) 拆成若干个有序的正整数之和。同时记 \(f\) 为斐波那契数列。
定义一个 lqp 拆分的权值为:它拆出来的所有数为 \(a_1\sim a_m\),权值为 \(f_{a_1}\cdot f_{a_2}\cdot\dots\cdot f_{a_m}\),求 \(n\) 的所有 lqp 拆分的权值和。\(n\le 10^{100000}\)。
令 \(g_n\) 为 \(n\) 的答案。则当 \(n>0\),\(g_n=f_n+\displaystyle\sum_{i=1}^{n-1}f_i\cdot g_{n-i}\)。
为了方便,令 \(g_0=1\),这样 \(f_n\) 可以表示为 \(f_n\cdot g_0\)。
如此,\(g_n=\displaystyle\sum_{i=1}^nf_ig_{n-i}(n>0)\)
还是考虑生成函数 \(G(x)\)。还是用上面的方法。
\(g_0=1,g_1x=(f_1g_0)x,g_2x^2=(f_2g_0+f_1g_1+f_0g_2)x^2,\dots\)。
但是直接加没有结果,把 \(g_0\) 改写为 \(1+f_0g_0\),这样可以得出 \(G(x)=F(x)G(x)+1\),其中 \(F(x)\) 是斐波那契数列的生成函数。(利用乘法法则!)
所以 \(1=G(x)(1-F(x))\),\(G(x)=\dfrac{1}{1-F(x)}\),又 \(F(x)=\dfrac{x}{1-x-x^2}\)(上面算过了)。
则 \(G(x)=\dfrac{1}{1-\dfrac{x}{1-x-x^2}}=\dfrac{1-x-x^2}{1-2x-x^2}\)。
怎么求 \([x^n]G(x)\)?
\((1-2x-x^2)G(x)=1-x-x^2\),我们尝试比较左右两边 \(x^n\) 的系数。(假设 \(n>2\))
右边系数为 \(0\),左边系数为 \(g_n-2g_{n-1}-g_{n-2}\),所以 \(g_n=2g_{n-1}+g_{n-2}\),初值 \(g_0,g_1\) 显然可以算。于是用矩阵快速幂就可以了。
从母函数推原递推式:比较系数法。
例2
随机生成 \(n\) 个结点的有根二叉树。问叶子个数的期望值。
令 \(c_n\) 为 \(n\) 个结点有根二叉树的个数,\(h_n\) 为 \(n\) 个结点有根二叉树的叶子总数。答案为 \(\dfrac{h_n}{c_n}\)。
\(c_n\) 怎么算?枚举左右两个子树的点个数,\(c_n=\sum c_{i}c_{n-1-i}\),这就是卡特兰数。
\(h_0=0\),\(h_1=1\),对于 \(n\ge 2\),\(h_n=2\displaystyle\sum_{i=0}^{n-1}h_ic_{n-1-i}\)。
为什么?考虑一颗二叉树的叶子个数,我们可以先计算左边的点数以及左边子树的叶子数量:\(h_i\),对于每一个左边子树的 \(h_i\),右边子树都有 \(c_{n-1-i}\) 种可能。所以左边子树贡献的叶子个数为 \(\sum h_ic_{n-1-i}\)。
右子树也是对称的,所以要乘 \(2\)。
那接下来怎么办呢?考虑 \(h,c\) 的母函数 \(H,C\)。因为 \(c_n\) 是卡特兰数序列,所以 \(C(x)=\dfrac{1-\sqrt{1-4x}}{2x}\)
还是等号左右相加。\(H(x)-h_0-h_1x=H(x)-x=2xH(x)C(x)\)。
\(H(x)=2xH(x)C(x)+x\)。
则 \(H(x)=\dfrac{x}{1-2xC(x)}=\dfrac{x}{1-2x\cdot\dfrac{1-\sqrt{1-4x}}{2x}}=\dfrac{x}{\sqrt{1-4x}}=x(1-4x)^{-\frac{1}{2}}\)。
广义二项式定理展开,\(H(x)=x\displaystyle\sum_{i=0}^{+\infty}(^{-\frac{1}{2}}_i)(-4x)^i\)。
则 \(h(n)=[x^n]H(x)=(^{-\frac{1}{2}}_{n-1})\cdot(-4)^{n-1}\),化简为 \((^{2n-2}_{n-1})\),化简过程略,就是展开 \((^{-\frac{1}{2}}_{n-1})\) 后和 \((-4)^{n-1}\) 把 \(\dfrac{1}{2}\) 抵消。
则 \(\dfrac{h(n)}{c(n)}=\dfrac{(^{2n-2}_{n-1})}{(^{2n}_n)/(n+1)}\).
拆分方案
题意:把 \(n\) 拆成若干 \(2,3,4\) 的和,不考虑顺序,求方案数。
\(G(x)=(1+x^2+x^4+\dots)(1+x^3+x^6+\dots)(1+x^4+x^8+\dots)=\dfrac{1}{1-x^2}\dfrac{1}{1-x^3}\dfrac{1}{1-x^4}.\)
设 \(G(x)=g_0+g_1x+g_2x^2+\dots,H(x)=1/G(x)=(1-x^2)(1-x^3)(1-x^4)\)。显然 \(H(x)\) 很容易展开。
设 \(H(x)=h_0+h_1x+h_2x^2+\dots+h_9x^9\)。这里 \(h_0\sim h_9\) 都是可以求出来的。同时注意 \(h_0=1\)。(\((1-x^2)(1-x^3)(1-x^4)\) 的常数项当然是 \(1\))
\(G(x)H(x)=1\),因为倒数嘛。根据母函数的乘积 \(=1\),可以推出两个数列的卷积的关系。
观察 \(g_{n-9}h_9+\dots+g_nh_0=0\),这是一个线性齐次递推式!而且因为 \(h_0\sim h_9\) 都能求,所以 \(g_0\sim g_8\) 也能求。
对于 \(n\ge 9\),可以用矩阵快速幂搭配递推式,\(O(\log n\cdot 9^3)\) 的复杂度。
这里采用倒数的方法,原因是倒数的形式简单,而且线性齐次递推式的项数比较少。
CF506E子问题
题意:
\(p\) 个字符串 \(s_1\sim s_p\),由字符a
到x
组成。
\(q\) 个字符串 \(t_1\sim t_p\),由字符a
到y
组成。
\(1\) 个字符串 \(R\),由a
到z
组成。
已知总长度和为 \(l\),允许空串。求方案数。\(p,q\le 200\)。
令 \(G(x)=(1+24x+24^2x^2+\dots)^p(1+25x+25^2x^2+\dots)^q(1+26x+26^2x^2+\dots)^1\)。\(ans=[x^l]G(x)\)。
而 \(G(x)=(1-24x)^{-p}(1-25x)^{-q}(1-26x)\)。如果和上面一样采取倒数的 trick,可以做到 \(O(\log L\cdot 401^3)\)。
UOJ424
题意:左拐度 \(<m\) 的 \(n\) 个结点二叉树计数。定义左拐度为所有根到叶子的路径中,向左走的次数的最大值。\(n,m\le 10^5\)。
设 \(f_{n,m}\) 表示左 \(<m\)(注意是小于不是小于等于),结点数 \(=n\) 的二叉树个数。
观察 \(F_{n,m}=\displaystyle\sum_{i=0}^{n-1}F_{i,m-1}F_{n-1-i,m}\) 的形式,是一个卷积,所以考虑使用母函数。
令 \(F_m(x)\) 为 \(<F_{1\sim n,m}>\) 的母函数.
类似地,可以推出 \(F_m(x)=xF_{m-1}(x)\cdot F_m(x)\),\(F_m(x)=\dfrac{1}{1-xF_{m-1}(x)}\)。
如果暴力从 \(F_1(x)\) 算到 \(F_m(x)\),复杂度会爆。
显然 \(F_m(x)\) 能写成 \(\dfrac{A_m(x)}{B_m(x)}\) 的形式。而且可以发现,\(A_{m+1}(x)=B_m(x)\)。因此我们只需要记录每一个 \(B_i(x)\) 即可,\(A_i(x)\) 可以用 \(B_i(x)\) 求出来。
\(F_{m+1}(x)=\dfrac{1}{1-x\cdot \dfrac{B_{m-1}(x)}{B_m(x)}}=\dfrac{B_m(x)}{B_m(x)-xB_{m-1}(x)}\)。
则 \(B_{m+1}(x)=B_m(x)-xB_{m-1}(x)\)。这又是一个递推式。
我们想用矩阵快速幂:因为这是一个线性齐次递推式。但是如果矩阵的元素是多项式,很麻烦;可以使用拉格朗日插值公式,随便选 \(m\) 个 \(x\) 代入,得到 \(B_{m}(x)\) 的 \(m\) 个值,进而推出 \(B_{m}(x)\) 的整个多项式。
\(F_{m}(x)=\dfrac{B_{m-1}(x)}{B_{m}(x)}\),同理求出 \(B_{m-1}(x)\) 的整个多项式,用 \(O(n\log n)\) 的复杂度算出 \(F_{m}(x)\),然后 \([x^n]F_{m}(x)\) 就是 \(F_{n,m}\) 的值。