生成函数(小名母函数)
母函数定义
对于序列a0,a1,a2,...构造一函数:
称函数G(x)是序列a0,a1,a2,...的母函数
下面导入一个问题:若有1g,2g,3g,4g的砝码各一枚,能称出哪几种重量?有几种可能方案?
解决:构造母函数:用x的指数表示称出的重量,则:对于砝码的组合情况,可以用几个函数的乘积表示:
乘积式中的1,代表不取,指数代表砝码重量
多项式中,x的指数代表称出的重量,x的系数代表方案数,项数代表能称出来的重量种数
导入问题2:用1分,2分,3分的邮票贴出不同数值的方案数(邮票可重复)
则母函数:
常用问题::整数拆分
将一个数n拆分成1,2,3,...,m的和,求有多少种拆分数
故有
代码实现:
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int c1[N],c2[N];
int main()
{
int n,i,j,k;
while(cin>>n)
{
for(int i=0;i<=n;i++)
{
c1[i]=0;
c2[i]=0;
}
for(int i=0;i<=n;i++)
c1[i]=1;
for(int i=2;i<=n;i++)
{
for(int j=0;j<=n;j++)
for(int k=0;k+j<=n;k+=i)
c2[j+k]+=c1[j];
for(int j=0;j<=n;j++)
{
c1[j]=c2[j];
c2[j]=0;
}
}
cout<<c1[n]<<endl;
}
return 0;
}
数组c1用来记录每次展开后项的系数,数组c2用于记录临时计算结果,下标用来表示指数。对于c1数组初始化先为0,后赋值为1:因为在本情况下第一项是
中间只隔了一次,当然如果将这一个删掉(将n拆分不可用1),第一项就是
那么c1的初始化就应该是1010101010.......
指数型母函数
导入问题:n个元素组成的多元集,a1重复n1次,a2重复n2次...,现取r个数进行排列,若n=r,则不同的排列数有:
于是引入指数型母函数:
对于,
表示k个数不同排列的排列数,a表示组合数
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
double c1[N],c2[N];//注意类型
int val[N],f[N];
void factorial()
{//求阶乘
f[0]=1;//初始化
for(int i=1;i<=20;i++)
f[i]=f[i-1]*i;
}
int main()
{
int n,i,j,k;
factorial();//预处理
while(cin>>n>>m)
{
for(int i=0;i<m;i++)
cin>>val[i];
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
for(int i=0;i<=val[0];i++)
c1[i]=1.0/f[i];//指数函数乘积项系数
for(int i=1;i<=m;i++)
{
for(int j=0;j<=n;j++)
for(int k=0;k+j<=n&&k<=val[i];k++)
c2[j+k]+=c1[j]/f[k];//构造指数函数
for(int j=0;j<=n;j++)
{
c1[j]=c2[j];
c2[j]=0;
}
}
cout<<c1[n]*f[n]<<endl;//最后乘以m的阶乘
}
return 0;
}
与上面差不多,改动的都已标记,不过更多的还是要灵活运用