母函数(思想而非套路)
普通母函数:
可以用来求解一些组合数问题,例如最经典的x中砝码可以构成重量为y方案数有多少?
普通的话穷举所有的方案数是2^n的复杂度,指数级增长很快
但是利用母函数的话,可以转换成一个幂级数的乘积的形式,转换方案见代码,可以将复杂度降低到n^3,是一个幂级数复杂度,远低于指数级复杂度
题目如下:
/* 普通母函数:将离散数列的构造简化为幂级数 例子:现在1g 3g 5g 9g 的砝码各有无限个,问构成13g的方案数有多少 我们知道1g的可以选择1个,2个,3个...13个 我们用x1 x2 x3...x13代表 3g的可以选择1个,2个,3个,4个,我们用x3 x6 x9 x12代表 5g 9g 同理 下角标代表的是重量 前面的标号就是方案数 于是我们可以列出来算式就是(x1+x2+x3+x4+..+x13)*(x3+x6+x9+x12)*(x5+x10)*(x9)=...=a*x2+b*x5=a*b*x7 之后求13的方案数就是x13的系数 为什么称之为母函数呢 实际上是一种思想 就是一种将离线序列转换为幂级数的方案 */ #include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; int maxx; int n; int a[100]; int sug[100]; ///保存每个值的系数 int tmp[100]; ///保存临时结果 int main() { while( scanf("%d" , &n)!=EOF ) { scanf("%d" , &maxx); for(int i=1; i<=n; i++) { scanf("%d" , &a[i]); } memset(tmp , 0 , sizeof(tmp)); for(int i=0; i<=maxx; i+=a[1]) ///从0开始因为可以不选这个 { sug[i] = 1; } for(int i=2; i<=n; i++) { for(int j=1; j<=maxx; j++) { for(int k=0; k<=maxx; k+=a[i]) { tmp[j+k] += sug[j]*1; } } for(int j=1; j<=maxx; j++) { sug[j] = tmp[j]; tmp[j] = 0; } } for(int i=1; i<=maxx; i++) printf("%d..%d..\n" , i , sug[i]); ///输出组成每种重量的方案数 } return 0; }
指数型母函数:
用来求解多重集的排列问题
指数型母函数:(用来求解多重集的排列问题)
n个元素,其中a1,a2,····,an互不相同,进行全排列,可得n!个不同的排列。
若其中某一元素ai重复了ni次,全排列出来必有重复元素,其中真正不同的排列数应为 ,即其重复度为ni!
同理a1重复了n1次,a2重复了n2次,····,ak重复了nk次,n1+n2+····+nk=n。
对于这样的n个元素进行全排列,可得不同排列的个数实际上是
若只对其中的r个元素进行排列呢,那就用到了指数型母函数。
构造母函数G(x)=+则称G(x)是数列a0,a1…an的指数型母函数。
一般过程:
1.建立模型:物品n种,每种数量分别为k1,k2,..kn个,求从中选出m个物品的排列方法数。
2.构造母函数:G(x)=(1+ + …+)(1+ ++…)…(1+ ++…)
=a0+a1·x+ · + · +… · (其中pp=k1+k2+k3…kn)
G(x)含义:ai为选出i个物品的排列方法数。
若题中有限定条件,只要把第i项出现的列在第i项的式中,未出现的不用列入式中。
如:物品i出现的次数为非0偶数,则原式改为…*( + + )*…
感谢:https://blog.csdn.net/yu121380/article/details/79914529