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}\)

\[\begin{aligned} h_0&=h_0\\ h_1x&=h_1\cdot x\\ h_2x^2&=2(h_0c_1+h_1c_0)x^2\\ h_3x^3&=2(h_2c_0+h_1c_1+h_0c_2)x^3\\ &\dots\\ \end{aligned} \]

还是等号左右相加。\(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\),可以推出两个数列的卷积的关系。

\[\begin{aligned} g_0h_0&=1\\ g_0h_1+g_1h_0&=0\\ g_0h_2+g_1h_1+g_2h_0&=0\\ &\dots\\ g_{n-9}h_9+\dots+g_nh_0&=0(n\ge 9)\\ \end{aligned} \]

观察 \(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\),由字符 ax 组成。
\(q\) 个字符串 \(t_1\sim t_p\),由字符 ay 组成。
\(1\) 个字符串 \(R\),由 az 组成。
已知总长度和为 \(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\) 的二叉树个数。

\[\begin{cases} F_{n,0}=[n=0]\\ F_{n,1}=1\\ F_{n,m}=\displaystyle\sum_{i=0}^{n-1}F_{i,m-1}F_{n-1-i,m}&\text{(枚举左右子树)} \end{cases} \]

观察 \(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}\) 的值。

posted @ 2024-03-23 08:59  FLY_lai  阅读(31)  评论(0编辑  收藏  举报