生成函数 应用
来源:互联网 发布:fft算法 c语言 编辑:程序博客网 时间:2024/05/18 22:40
引言
生成函数有普通型生成函数和指数型生成函数两种,其中普通型用的比较多。形式上说,普通型生成函数用于解决多重集的组合问题,而指数型母函数用于解决多重集的排列问题。
因水平有限,此博客涉及的均是生成函数的初级应用,用于解决相关的算法竞赛题目。
斐波那契函数的通项公式
考虑一个经典问题:
求斐波那契函数的通项。
此问题的结论了解斐波那契函数的人都知道,那就是:
此结论初看好像在算法竞赛中没什么用,因为对于求斐波那契函数第n项的值,存在一个经典的算法,那就是矩阵快速幂。而且因浮点数存在误差,故计算机并不能精确计算出该公式的值。
但通过对此公式的深入了解和推导证明,我们将对斐波那契函数有更深的理解,并将矩阵快速幂和生成函数两个算法进行联系。
下面我们试着来推导这个公式。
首先从熟悉的矩阵快速幂来入手。
由递推关系式,可以构造矩阵:
通过观察已知,这其实也是一个递推式,逐层递推易得:
假设:
故问题的关键便在于如何求解
在算法竞赛中,常用的手段是利用计算机的强大计算能力和快速幂的思想来求解。
但实际上,在数学层面还有一个更加常用的方法来求解方阵的n次方,那就是矩阵的相似对角化。
由定义:
故
因:
故推出:
下面我们便来尝试将M矩阵相似对角化:
由
将
将上述矩阵代入(2)式,得:
然后将
当然本博客主要是讲解生成函数,所以接下来我们会通过生成函数的角度重新推导一遍该通项公式,但实质上两个方法是相似而又存在联系的。
生成函数我个人理解是通过代数的方法来解决组合数学的问题。
首先由生成函数的定义,可以得出斐波那契数列的生成函数为:
下面考虑如何化简该无穷级数。
考虑G(x)的第n项
由递推关系式
又因为G(x)的第n-1项和第n-2项分别是:
故第n-1项乘上
故推出:
移项后得出:
接下来再将G(x)展开为幂级数,那么
因已知
故我们尝试着将G(x)裂项展开:
利用待定系数法:
假设:
化简得出:
对比(3)式,解方程得出:
对比矩阵法,这个r和s恰好就是M矩阵的两个特征值。
另外解得:
综上所述:
故第n项的系数为:
求组合方案数
(1)买水果
其实这类题的解法都很类似,主要是对于生成函数求解方案数原理的深刻理解。
才接触母函数或叫做生成函数时,很多人都会被x的各种次方吓住,其实我们构造指数型的生成函数,
比如我们考虑一个买水果的问题:
现有三种水果:苹果,梨子和西瓜。其中买苹果的数量必须为偶数个,梨子的数量必须为3的倍数,西瓜的数量不多于4个,问买n个水果,有多少种方案数?
首先考虑苹果,记
已知
现在我们希望能方便地统一表示n的所有取值对应的方案数。
我们构建一个幂级数,其中
设该幂级数为
则
此时
同理,对于梨子:
而对于西瓜:
我们构建一个新的函数
先直接说结论:
我们可以这么来理解这件事。
假如我们买3个水果,此时的方案数一定包含两个苹果和一个西瓜。
两个苹果的方案数对应在
一个西瓜的方案数对应在
两个系数对应相乘便是买两个苹果和一个西瓜的方案数。同时
例题 HDU 2152
代码:
#include<cstdio>#include<cstring>#include<cstdlib>#include<queue>using namespace std;typedef long long ll;const int A = 100 + 10;int c1[A],c2[A];int l[A],r[A];int main(){ int n,m; while(~scanf("%d%d",&n,&m)){ for(int i=1 ;i<=n ;i++){ scanf("%d%d",&l[i],&r[i]); } memset(c1,0,sizeof(c1)); memset(c2,0,sizeof(c2)); for(int i=l[1] ;i<=r[1]&&i<=m ;i++) c1[i] = 1; //初始化 for(int i=2 ;i<=n ;i++){ //枚举其他水果 for(int j=0 ;j<=m ;j++){ //模拟多项式乘法过程 for(int k=l[i] ;k<=r[i] && j+k<=m ;k++){ c2[j+k] += c1[j]; } } for(int j=0 ;j<=m ;j++){ c1[j] = c2[j]; c2[j] = 0; } } printf("%d\n",c1[m]); } return 0;}
(2)砝码称重问题
考虑一个称重问题:
假设我们现在要称重一个质量为n的物体,现在有三个砝码,分别重为a1,a2,a3,砝码可放在天平的左侧或右侧。问称出这个质量为n的物体有多少种不同方案。
此问题跟上一个问题类似,我们同样可以构建三个生成函数:
然后相乘之后求
(3)整数的划分
整数的划分问题也是求方案数,下面举一个例子:
对于3,有3 = 1 + 1 + 1 = 1 + 2 = 3
故有三种划分方案。
对于求整数n的划分数
可以看成是有n个无区别的小球,放进任意个非空的盒子里,求方案数
此题也可以用生成函数来求解,我们来考虑整数1-n的贡献。
对于数字1:每次可以贡献1
对于数字2:每次可以贡献2
以此类推
然后将1-n所有数字的生成函数乘起来,求
当然,敏锐的人能够发现,当n很大时,计算量可以说是爆炸的。
所以实际上,这个经典问题可以考虑DP求解。
设
则
这个递推表达式的由来不是本博客的重点= = 有兴趣的可以自己百度
拓展:上述问题是看成无区别的物品划分,若是有区别的物品划分方案数,则是一个经典数论知识:Bell数。Bell数的生成函数G(x)为:
(待更新)
参考资料:
知乎问答
百度百科
Matrix67博客
参考博客
- 生成函数 应用
- 生成函数(母函数)的简单应用
- 浅谈递推与生成函数的应用
- 生成函数
- 生成函数
- 生成函数
- 生成函数
- 生成函数
- 生成函数
- 生成函数
- 递归函数应用:根据树结点id,结点内容,父结点id,生成XML格式字符串
- pbfunc外部函数扩展应用-直接在Datawindow中生成QR二维码
- CodeForces 438E The Child And Binary Tree NTT模板 生成函数应用
- 函数应用
- 函数应用
- 函数应用
- 函数应用
- DLL的生成应用
- Java用socket实现简单的一对一通信
- 浅谈可重入函数与不可重入函数
- 一个高效、稳定、强大的Android刷新库
- 记一次阿里面试
- 关于选择脚本的问题
- 生成函数 应用
- Java Colections 集合类 —— List、ArrayList、Set(HashSet)
- leetcode 417. Pacific Atlantic Water Flow
- 通知与协议代理的区别
- 用PLSQL给自己发一份邮件
- Big Data (2)
- Java中String,StringBuffer都是final类
- Centos7中docker开启远程访问(Centos7 docker remote access configure)
- 蓝牙SIG公布Bluetooth MESH联网能力