这是一篇即将咕咕很久的学习笔记。
定义f(x)=a0+a1x+a2x2+a3x3...,f(x)就是序列a0,a1,a2...an的生成函数
01背包问题
给你w1,w2,w3,...wn,每个数只有取和不取的两种状态,求凑成W的种类数。
构造f(x)=∏i=1n(x0+xwi),于是答案就是xW的系数。
完全背包问题
给你w1,w2,w3,...,wn,每个数可以取任意多种,求凑成W的种类数。
构造f(x)=∏i=1n(∑j=0xwi×j),答案就是xW的系数。
∑j=0xwi×j是无穷的,如何算出?
令p=xiw,那么有∑j=0xwi×j=∑j=0pj。
注意到∑j=0pj=1−p1−p∞,当x∈(−1,1)时,p∈(−1,1),所以p→0,于是原式就是1−p1,即1−xiw1。
两种生成函数
前面介绍了第一种生成函数:∑j=0xj=1−x1(x∈(−1,1))
现在介绍第二种中的一个特殊情况:∑j=0(j+1)×xj=?
我们把两个∑j=0xj相乘,凑成j的有(0,j),(1,j−1)...(j,0)这么多种,共j+1种选法。
于是∑j=0(j+1)×xj=(x−1)21
推广一下:
(x−1)k1是什么?
问题转化为凑出k个数,使他们的和为j的方案数。
插板法即可,答案为Cj+k−1k−1
于是(x−1)k1=∑j=0Cj+k−1k−1xj
注意到Cj+k−1k−1=Cj+k−1j,这个形式在下面的广义二项式定理里面会用到。
于是我们总结出以下规律:
1−xk1=∑j=0xjk
(1−x)k1=∑j=0Cj+k−1k−1xj
还有一个有限项数的求和公式:
1−x1−xk+1=∑j=0kxk
广义二项式定理
注意到(1−x)k1=(1−x)−k。
我们不禁有个大胆的想法,如果k可以取任何实数,那么我们就可以表示出1−x,31−x等等的生成函数。
(1+x)α=∑j=0Cjαxj。
定义:
Cαk=⎩⎪⎨⎪⎧k!α(α−1)(α−2)…(α−k+1),k>11,k=00,k<0(k∈Z,α∈R)(1.1.1)
来自巨佬ypy的博客。
生成函数的应用
例题1
BZOJ 3028
承德汉堡:f(x)=1+x2+x4+x6...=1−x21
可乐:f(x)=1+x
鸡腿:f(x)=1+x+x2=1−x1−x3
蜜桃多:f(x)=∑j=0xj−(1+x2+x4+...)=1−x1−1−x21=1−x2x
鸡块:f(x)=1−x41
包子:f(x)=1+x+x2+x3=1−x1−x4
土豆片炒肉:f(x)=1+x
面包:f(x)=1−x31
乘起来然后大力化简一波,化成了(1−x)4x
套进第二个式子:
(1−x)4x=∑j=0Cj+33xj+1=∑j=1Cj+23xj
于是我们所求的就是Cj+23。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include <bits/stdc++.h> #define MAXN 200005 #define MOD 10007 using namespace std; inline int read(){ int x=0,f=1; char ch=getchar(); while (ch<'0'||ch>'9'){ if (ch=='-') f=-1; ch=getchar(); } while (ch>='0'&&ch<='9'){ x=((x<<3)+(x<<1)+(ch^'0'))%MOD; ch=getchar(); } return x*f; } inline int ksm(int b,int k){ int ans=1; while (k){ if (k&1) ans=(ans*b)%MOD; b=(b*b)%MOD; k>>=1; } return ans; } int main(){ int n=read(); printf("%d\n",(n+2)*(n+1)%MOD*(n)%MOD*ksm(6,MOD-2)%MOD); }
|
例题2
P2000 拯救世界
本质和上面一题是一样的:
kkksc03:
金:1−x61
木:1−x1−x10
水:1−x1−x6
火:1−x41
土:1−x1−x8
lzn:
金:1−x21
木:1+x
水:1−x81
火:1−x101
土:1−x1−x4
大力乘起来,算出1−x51
答案即是Cn+5−15−1=Cn+44。
只写了python版本:
1 2
| n=(int)(input()) print((n+1)*(n+2)*(n+3)*(n+4)//24)
|
例题3
试用生成函数推导斐波那契数列通项公式。
斐波那契数列:fib1=1,fib2=1,fibi=fibi−1+fibi−2(i≥3)
构造f(x)=∑j=1fibjxj
所以f(x)×x=∑j=2fibj−1xj
f(x)−f(x)×x=fib1x+∑j=3fibj−2xj=x+x2×f(x)
所以f(x)=1−x−x2x
令ϕ=21+5,ϕ′=21−5。
分解:1−x−x2x=(1−ϕ′x)(1−ϕx)x=51(1−ϕx1−1−ϕ′x1)
根据公式1−x1=∑j=0xj,前面一项化为(ϕ)n后面一项化成(ϕ′)n。
于是我们得到fibn=51(ϕn−ϕ′n)。
即fibn=−51(21−5)n+51(21+5)n。
补充
已知f0=A,f1=B,fi=pfi−1+qfi−2(i≥2)
构造f(x)=∑j=1fjxj
所以f(x)×x=∑j=2fj−1xj
得到f(x)−pf(x)×x=Cx+∑j=2fj−2xj=Cx+qx2f(x)(其中C是一个常数,我们可以不用管它,原理在你使用时自然清楚)
得到f(x)−pxf(x)−qx2f(x)=Cx,于是有f(x)=1−px−qx2Cx。
设方程x2−px−q=0的解是x1,x2(x1,x2又称特征根),注意到把x=x11带入1−px−qx2,变成1−x1p−x12q=x12x12−px1−q
显然为0。
于是可以转化为fn=C1x1n+C2x2n
你肯定有疑问,为什么不算出来C1,C2,直接无脑带进去就好。
事实上C1,C2公式非常复杂,你肯定也记不住。
考试时,可以解出C1,C2。
比如一道题:h0=1,h1=3,hn=2hn−1+2hn−2(n≥2)。
特征根:x2−2x−2=0→x1,2=22±4+8=1±3
带入h0=C1+C2,h1=C1x1+C2x2(这里我们特意算出来h0以简化计算)
得到C1+C2=1,C1(1+3)+C2(1−3)=3
解得C1=623+3,C2=6−23+3
通项公式hn=623+3(1+3)n+6−23+3(1−3)n
例题4
试用生成函数推导卡特兰数通项公式。
卡特兰数:
c0′=1
c1′=1
cn′=∑i=1n−1ci′cn−i−1′
为了方便,记ci=ci−1′,有ci′=ci+1。
所以有cn=cn−1′=∑i=1n−2ci′cn−i−2′=∑i=1n−2ci+1cn−i−1=∑i=2n−1cicn−i
记C(x)=∑i=0cixi
有C(x)−C(x)2=C1×x1=x。
于是C(x)2−C(x)+x=0
得到C(x)=21±1−4x
舍去21+1−4x
所以C(x)=2x1[1−(1−4x)0.5]
先化简(1−4x)0.5
由(1+x)α=∑j=0Cjαxj
有(1−4x)0.5=∑j=0C0.5j(−4x)j。
注意到这里C0.50(−4x)0=1,把它放到前面去。
拆一波C0.5j=j!∏k=0j−1(0.5−k)
放回去:∑j=1j!∏k=0j−1(0.5−k)×(−4x)j
右边除掉一个(−2)j,左边乘(−2)j
变成:∑j=1j!∏k=0j−1(2k−1)×(2x)j
注意到∑k=0j−1=−1×(1×3×5×...×(2j−3)),这里我们把那个−1放到前面抵消掉减号,下面不再说明。
这时可以发现(1×3×5×...×(2j−3))=2j−1(j−1)!(2j−2)!
于是我们可以得到(1−4x)0.5=1−∑j=12jxj×2j−1(j−1)!(2j−2)!×j!1
等于1−∑j=1xj×2(j−1)!j!(2j−2)!
带回原式C(x)=2x1[1−(1−∑j=0xj×2(j−1)!j!(2j−2)!)]
等于∑j=1xj−1×(j−1)!j!(2j−2)!。
注意到x的次数不能是j−1,于是把k=j−1带入,变成∑k=0xk×k!(k+1)!(2k)!
于是得到公式cn=n!(n+1)!(2n)!