初学生成函数(一)——普通生成函数
前言
生成函数是一个非常好用的东西。
但由于我数学基础太差,因此就一直学不会。又想到我不太理解多项式乘法,即便学会也用不了,就没有继续坚持学习。
但是,这次我总算找到一篇比较良心的博客,也终于算是对生成函数初步入门了。
从一个简单的背包问题开始
考虑这样一个问题:
有\(4\)种物品,每种物品的个数分别为:\(\{1,2,3,1\}\)。定义两个选择物品的方案不同当且仅当存在至少一种物品选择的个数不同,求选出\(5\)个物品的方案数。
如果你会动态规划,那么用背包就可以轻松解决此题,这里就不多说了。
现在我们的重点是,如何用生成函数的思维来解决这个问题。
基本生成函数的意义
考虑我们把每种物品表示成一个多项式(其实就是生成函数):\(\sum_{i=0}^{+\infty}a_ix^i\)。
其中\(i\)次项\(x^i\)的系数\(a_i\),表示选出\(i\)个物品的方案数。而这里的\(x\),并没有任何意义。
对于第\(1\)种物品,只有两种选择:不选或选\(1\)个,方案数都是\(1\)。我们可以用一个多项式把它表示为\(x^0+x^1\)(即\(1+x\))。
对于第\(2\)种物品,共有三种选择:不选或选\(1\)个或选\(2\)个。我们同样可以用一个多项式把它表示为\(1+x+x^2\)。
对于第\(3\)种物品,共有四种选择:不选或选\(1\)个或选\(2\)个或选\(3\)个。我们依然可以用一个多项式把它表示为\(1+x+x^2+x^3\)。
对于第\(4\)种物品,只有两种选择:不选或选\(1\)个。我们照旧可以用一个多项式把它表示为\(1+x\)。
所以,我们成功地把这\(4\)种物品变成了\(4\)个多项式。
接下来,我们先探讨一下多项式乘法的本质是什么。
例如我们要把\(\sum_{i=0}^{+∞}a_ix^i\)和\(\sum_{i=0}^{+∞}b_ix^i\)乘起来,则我们可以分别在两个多项式中枚举每一项。
假设在第一个多项式中枚举到\(a_ix^i\),在第二个式子中枚举到\(b_jx^j\),那么我们就会在表示答案的多项式中加上一项\(a_ib_jx^{i+j}\)。
考虑这一操作的实际意义,其实就是:若我们在第一种物品中选出\(i\)个,第二种物品中选出\(j\)个,总共就选出了\(i+j\)个,因此将选出\(i+j\)个物品的方案数加上在第一种物品中选出\(i\)个的方案数与在第二种物品中选出\(j\)个的方案数的乘积。
这似乎带给我们一些启发。也就是说,将两个多项式相乘后,它第\(i\)次项系数的实际意义,依然符合我们的初衷。
如果我们把上面例子中的\(4\)个多项式乘起来,就可以得到:
这个多项式的系数为\(\{1,4,8,11,11,8,4,1\}\),也就分别代表了选出\(0\sim7\)个物品的方案数。
于是我们就回答了上面那个问题,即选出\(5\)个物品的方案数为\(8\)。
至此,对于基本生成函数的意义,就基本解释完了。
但是,基本生成函数究竟有什么用呢?从上面的例子可以看出,它似乎并没有对时间复杂度起到任何优化。
这就需要对它的进一步转化了。
基本生成函数的进一步转化
基本生成函数的进一步转化涉及到一个公式推导,即在\(x∈(-1,1)\)时,\(\sum_{i=0}^{+∞}x^i=\frac1{1-x}\),证明如下:
设\(S=\sum_{i=0}^{+∞}x^i\),则\(xS=\sum_{i=1}^{+∞+1}x^i\)。
由于\(+∞+1\)依然可以被视作是无穷大,所以我们可以认为\(xS=\sum_{i=1}^{+∞}x^i\)。
则\(xS-S=\sum_{i=1}^{+∞}x^i-\sum_{i=0}^{+∞}x^i=-1\),即\((x-1)S=-1\)。
所以\(S=\frac{-1}{x-1}=\frac1{1-x}\)。
这样一来,我们就把一个多项式给化成了一个简单的式子。
注意,这里虽然多出了\(x∈(-1,1)\),可正如前面所说,\(x\)没有任何意义,因此多出这个限制并没有任何关系。
而实际上,有了这一个转化,我们就能够让生成函数发挥更多的作用。
基本生成函数的简单应用
根据一些简单的变换,我们就可以得到一些常见限制与生成函数之间的转化关系。
-
要求选出的数不能超过\(k\):\(\sum_{i=0}^kx^i=\frac{1-x^{k+1}}{1-x}\)。
-
要求选出的数必须是\(k\)的倍数:\(\sum_{i=0}^{+∞}x^{ik}=\sum_{i=0}^{+∞}(x^k)^i=\frac1{1-x^k}\)。
同时,我们还必须知道一个重要而又实用的公式:\(\frac1{(1-x)^k}=\sum_{i=0}^{+∞}C_{i+k-1}^{k-1}x^i\)。
简单而言,就是生成函数\(\frac1{(1-x)^k}\)的\(i\)次项的系数就是\(C_{i+k-1}^{k-1}\),证明如下:
\(\frac1{(1-x)^k}=(\frac1{1-x})^k=(\sum_{i=0}^{+∞}x^i)^k\)
设最终的\(x^i\)的产生方式为\(x^i=\prod_{p=1}^kx^{a_p}\),则\(x^i\)的系数其实就相当于求出有多少个长度为\(p\)的数组\(a\)满足:
- \(\sum_{p=1}^ka_p=i\)。
- 对于任意\(p(1\le p\le k)\),满足\(a_p\ge 0\)。
这其实就是求把\(i\)个物品分成\(k\)个可为空集合的方案数,我们可以用隔板法来求出。
考虑这一过程就相当于在\(i\)个物品中选出\(k-1\)个缝隙(可重复),插入\(k-1\)块板。
而共有\(i+1\)个缝隙可供插入,若把每个缝隙看成一个新的物品,并再加入\(k-2\)个新物品其中第\(t\)个表示第\(t+1\)块板是否会与第\(t\)块板放在一起。
所以就相当于在\((i+1)+(k-2)=i+k-1\)个物品中选出\(k-1\)个物品,方案数就是\(C_{i+k-1}^{k-1}\)。