定义
在数学中,某个序列的母函数(Generating function,又称生成函数)是一种形式幂级数,其每一项的系数可以提供关于这个序列的信息。使用母函数解决问题的方法称为母函数方法。
详解
以下内容参考Tonyyy的博客。
首先举一个经典的例子。
现有质量为1, 2, 3的砝码各一枚,问:
(1)可以称出多少种不同质量的物品。
(2)要称出质量为3的物品,有多少种方案。
解:
在数字逻辑中我们使用 + 代表或逻辑,* 代表与逻辑,这里我们同样的含义。
(使用1g+不适用1g) * (使用2g+不适用2g) = (使1 * 使2) + (使1 * 不使2) + (不使1 * 使2) + (不使1 * 不使2)
通过上面可以看到逻辑运算和我们普通算数的多项式计算是相似的。那我们可不可以把这样一个逻辑运算使用多项式表达出来呢?**再回到题目,最后的两个砝码的计算实际是一个加法运算,那么有没有这样一个运算是乘法变加法。不难想到幂乘,xm * xn = xm+n。**这样就使用幂次当作质量,因此1g的砝码可以写为 (x0 + x1) = (1 + x1),其中x0的零次方就代表了不使用质量为1的砝码。
(1)这样的话答案就变为了(1+x) * (1+x2) * (1+x3) = 1 + x + x2 + 2x3 + x4 + x5 + x6。
上面我们定义是x的幂次代表质量,因此,共可以称6种质量的物品,分别是从1——6g。
(2)x3前面的系数为2,因此有两种方法可以称出质量为3的物品。
如果三个砝码的数量是无限的,那么1g就可以表示为(1+x1 + x2…+xn),代表可以称的质量,2g表示为(1 + x2 + x4 + x6 + …x+x2n)。
因此构造的母函数就变为了G(x) = (1 + x + x2…)(1 + x2 + x4…)(1+x3 + x6…)…
例题
例题一
题解
通过上面的证明我们可以直接构造出来母函数,G(x) = (1+x+x2+x3 +…+xx1)(1+x2 + x4 + x6 +…+x2x2)…(1 + x + x26 + x52 +…+x26x26)
母函数有了就可以直接通过一个递推来求解每个多项式乘后的结果,由于题目要求价值不大于50,因此我们只需要计算到x50即可。
ac代码
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int a[60], b[60];
int n;
scanf("%d", &n);
while (n--) //n个样例
{
int num;
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
a[0] = 1;
for (int i=1; i<=26; i++) //总共输入26个字母的个数
{
scanf("%d", &num);
for (int j=0; j<=50; j++) //这里就是进行多项式模拟,可以在纸上推一下
{
for (int k=0; k<=num && k*i+j<=50; k++) //k表示第j个指数,所以k每次增加i
{
b[k*i+j] += a[j];
}
}
for (int j=0; j<=50; j++)
{
a[j] = b[j];
b[j] = 0;
}
}
int total = 0;
for (int i=1; i<=50; i++)
total += a[i];
printf("%d\n", total);
}
return 0;
}
例题二
题目大意
给你一个整数,问你有多少种拆分方法。
解题思路
这个题和上面的母函数题其实是一样的,上面的是给定质量的砝码,本题的砝码只不过从给定的变为了1-n了,并且数量是没有要求的,只要总质量等于n即可。
因此构造出来的母函数和上一个题大同小异,G(x) = (1 + x 1 + x2 +…xn)(1 + x2 + x4 …+xn/2)(1 + x3 + x6 +…+xn/3)…(1 + xn)
ac代码
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int a[121], b[121];
int n;
while (~scanf("%d", &n))
{
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
a[0] = 1;
for (int i=1; i<=n; i++)
{
for (int j=0; j<=n; j++)
{
for (int k=0; k+j<=n; k+=i)
{
b[k+j] += a[j];
}
}
for (int j=0; j<=n; j++)
{
a[j] = b[j];
b[j] = 0;
}
}
printf("%d\n", a[n]);
}
return 0;
}