DAY_6(生成函数)

文章介绍了如何使用母函数方法解决涉及序列、权重组合、邮票排列和整数拆分等问题,通过构建指数型函数并利用代码实例展示了如何计算特定条件下的组合数和排列数。
摘要由CSDN通过智能技术生成

生成函数(小名母函数)

母函数定义

对于序列a0,a1,a2,...构造一函数:G(x)=a_{0}+a_1x+a_2x^2+...

称函数G(x)是序列a0,a1,a2,...的母函数

 下面导入一个问题:若有1g,2g,3g,4g的砝码各一枚,能称出哪几种重量?有几种可能方案?

解决:构造母函数:用x的指数表示称出的重量,则:对于砝码的组合情况,可以用几个函数的乘积表示:G(x)=(1+x)(1+x^2)(1+x^3)(1+x^4)=1+x+x^2+2x^3+2x^4+2x^5+2x^6+2x^7+x^8+x^9+x^{10}

乘积式中的1,代表不取,指数代表砝码重量

多项式中,x的指数代表称出的重量,x的系数代表方案数,项数代表能称出来的重量种数

导入问题2:用1分,2分,3分的邮票贴出不同数值的方案数(邮票可重复)

则母函数:G(x)=(1+x+x^2+...)(1+x^2+x^4+...)(1+x^3+x^6+...)

常用问题::整数拆分

将一个数n拆分成1,2,3,...,m的和,求有多少种拆分数

故有  G(x)=(1+x+x^2+...)(1+x^2+x^4+...)...(1+x^m+x^{2m}+...)

代码实现:

#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用来记录每次展开后x^{n}项的系数,数组c2用于记录临时计算结果,下标用来表示指数。对于c1数组初始化先为0,后赋值为1:因为在本情况下第一项是(1+x+x^2+...)中间只隔了一次,当然如果将这一个删掉(将n拆分不可用1),第一项就是(1+x^2+x^4+...)那么c1的初始化就应该是1010101010.......

指数型母函数

导入问题:n个元素组成的多元集,a1重复n1次,a2重复n2次...n=n_1+n_2+n_3+...+n_k,现取r个数进行排列,若n=r,则不同的排列数有:\frac{n!}{n_1!n_2!...n_k!}

于是引入指数型母函数:

G_e(x)=(1+\frac{x}{1!}+\frac{x^2}{2!}+\frac{x^3}{3!})(1+\frac{x}{1!}+\frac{x^2}{2!})(1+\frac{x}{1!}+\frac{x^2}{2!}+\frac{x^3}{3!})

对于\frac{a}{b!}x^k\frac{a}{b!}表示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;
}

与上面差不多,改动的都已标记,不过更多的还是要灵活运用

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值