生成函数简介
生成函数 ( ext{(generating function)}),又称母函数,是一种形式幂级数,其每一项的系数可以提供关于这个序列的信息。
by wiki
用人话来说生成函数就是把一个序列变成了一个函数。
一个形如 (F(x) = sum_{n > 0}{a_n imes x^n}) 的函数可以理解为他是一个每一项分别为 (a_n) 的序列。
普通生成函数
重新引用上面的定义 (F(x) = sum_{n > 0}{a_n imes x^n})
这个 (n) 的定义域是到正无穷的,因为在序列的意义下,不存在的项的系数即为 (0),代回带函数里面也不影响。
关讲过于抽象,举几个栗子(我们定义 (a) 为序列, (F(x)) 为它的生成函数)。
-
(a = [1, 2, 3]) 则 (F(x) = 1 + 2 imes x + 3 imes x ^ 2)
-
(a = [1, 1, 1 …]) 则 (F(x) = sum_{n >= 0}{x ^ n})
-
(a = [1, 2, 4 …]) 则 (F(x) = sum_{n >= 0}{2 ^ n imes x ^ n})
-
(a = [1, 3, 5 …]) 则 (F(x) = sum_{n >= 0}{(2 imes x + 1) imes x ^ n})
通过上面的很多栗子,相信大家可以发现函数每一项的系数就是序列的每一项的值。
接下来有一些很 (naive) 的运算法则。
由于序列之间的运算是项项相对应的。
所以数字之间满足的运算法则,在生成函数里面也一样适用。
运算法则
1.加法运算:
考虑对于 (2) 个普通的生成函数,他们的生成函数为 (F(x)) 和 (G(x))
(F(x) + G(x) = sum_{(a_n + b_n)} imes x ^ n)
这样 (F(x) + G(x)) 是序列 (a_n + b_n) 的普通生成函数。
2.乘法运算:
考虑对于 (2) 个普通的生成函数,他们的生成函数为 (F(x)) 和 (G(x))
(F(x) imes G(x) = sum_{x ^ n} sum_{i = 0}^{n}{a_i imes b_{n - i}})
这样 (F(x) imes G(x)) 是序列 (a_n imes b_n) 的普通生成函数。
但是写太多 (sum) 会显得整个柿子特别的丑陋,所以就有了封闭形式。
以 (a = [1, 1, 1 …]) 为例,它的生成函数是 (F(x) = sum_{n >= 0}{x ^ n})
那么我们进一步化简可以得到 (F(x) * x + 1 = F(x))
移项可得 : (F(x) = frac{1}{1 - x})
就不再一一赘述,如果想要进一步理解的可以看 wiki 上的小练习,上面从从易到难,有求导,二项式定理,数学归纳法……运用。
斐波拉契数列
有一个非常著名而且经典的序列叫斐波拉契数列。
他的递推式是这个样子的:(f(x) = f(x - 1) + f(x - 2))
咋一看这个式子就感觉它很不好推是吧,但是我们有项数之间的数量关系对吧,那么就可以很容易的推出它的封闭形式。
(f(x) = x imes f(x) + x ^ 2 imes f(x) - a_0 imes x + a_1 imes x + a_0)
这个柿子可以理解为把 (f(x)) 右移一位和右移两位的结果相加,并且补上那些移项所消失的项。
即:(f(x) = frac{x}{1 - x - x ^ 2})
我们可以把封闭形式暴力分解:
(f(x) = frac{x}{1 - x - x ^ 2} = frac{x}{(1 - frac{1 - sqrt{5}}{2}) x imes (1 - frac{1 + sqrt{5}}{2}) x})
设 (u = frac{1}{1 - frac{1 - sqrt{5}}{2}}, v = sqrt{5})
那么原始可以化简为:(frac{x}{u imes (u + v)} = frac{u}{v} imes (frac{1}{u} - frac{1}{u + v}))
带回即可得 : (frac{x}{(1 - frac{1 - sqrt{5}}{2}x) imes (1 - frac{1 + sqrt{5}}{2}x)})
化简可得 : (frac{1}{sqrt{5}} imes ((frac{1 + sqrt{5}}{2}) ^ n) - (frac{1 - sqrt{5}}{2}) ^ n))
也就是我们常见的形式。
封闭形式转化为展开形式
先咕着
一些例题
洛谷P2000 拯救世界
题解:
经典的生成函数入坑题。
对于题目里描述的 (10) 种召唤方法,我们分别计算他的封闭形式并相乘,然后转化为展开形式并且求第 (n) 的系数就行了。
( ext{kkk}):
-
金:(1 + x ^ 6 + x ^ {12} … = frac{1}{1 - x ^ 6})
-
木:(1 + x ^ 2 + … + x ^ 8 = frac{1 - x ^ {10}}{1 - x})
-
水:(1 + x ^ 2 + … + x ^ 4 = frac{1 - x ^ 5}{1 - x})
-
火:(1 + x ^ 4 + x ^ 8 + … = frac{1}{1 - x ^ 4})
-
土:(1 + x ^ 2 + … + x ^ 6 = frac{1 - x ^ 6}{1 - x})
( ext{lzn})
-
金:(1 + x ^ 2 + x ^ {4} … = frac{1}{1 - x ^ 2})
-
木:(1 + x = frac{1 - x ^ {2}}{1 - x})
-
水:(1 + x ^ 8 + x ^ 16 = frac{1}{1 - x ^ 8})
-
火:(1 + x ^ 10 + x ^ 20 + … = frac{1}{1 - x ^ 10})
-
土:(1 + x ^ 2 + x ^ 3 = frac{1 - x ^ 4}{1 - x})
很多项都可以约掉,最后得到的就是:(frac{1}{(1 - x) ^ 5})
这个东西要怎么展开呢?
(frac{1}{(1 - x) ^ 5} = (frac{1}{1 - x}) ^ 5 = C_{n + 4} ^ {4} = (n + 1) imes (n + 2) imes (n + 3) imes (n + 4) / 24)
这个东西要用高精或者 ( ext{NTT}) ,当然 ( ext{ruby}) 还是更香的。