普通型母函数原理及模板代码详解

母函数有很多种,最常用的有普通型母函数和指数型母函数。两者区别是:普通型母函数主要是来求组合的方案数,而指数型母函数是求多重排列数。下面只讲解普通型母函数的相关知识。


定义

若函数G(x)=a0+a1*x+a2*x^2+……+an*x^n,则称函数G(x)为序列a0、a1、a2、……an的母函数。


例如:(1+x)^n=1+C(n,1)*x+C(n,2)*x^2+……+C(n,n)*x^n 就是序列 C(n,1)、C(n,2)、……、C(n,n)的母函数,其中C(n,m)为组合数。


经典例题

有质量为1,2,4的砝码分别为1,3,2枚,问:

1.可以称出多少种不同的质量?

2.要称出质量为3的物品,有几种可能的方式?


则可以构造函数G(x) = (1+x)*(1+x^2+x^4+x^6)*(1+x^4+x^8),其中第一个括号中的1表示质量为1的砝码用了0枚,x表示质量为1的砝码用了1枚;第二个括号中的1表示质量为2的砝码用了0枚,x^2为质量为2的砝码用了1枚,x^4表示质量为2的砝码用了2枚,也就是x^(2*2),x^6表示质量为2的砝码用了3枚,也就是x^(2*3)。先不必理解为什么这样做,只需要知道怎样做。


总结一下,每个括号就表示一种砝码的使用情况。x^n就表示质量为n的砝码用了1枚。最少可以使用0枚,也就是式子里面的1。最多可以使用m枚,也就是x^(n*m)。


知道了对应关系,那么代码应该怎么写呢?其实也简单,就是模拟手动计算以上多项式相乘的过程。比如上面的

G(x) = (1+x)*(1+x^2+x^4+x^6)*(1+x^4+x^8)

= (1+x^2+x^4+x^6  + x+x^3+x^5+x^7)*(1+x^4+x^8)

= (1+x+x^2+x^3+x^4+x^5+x^6+x^7)*(1+x^4+x^8)

= (1+x+x^2+x^3+x^4+x^5+x^6+x^7  +  x^4+x^5+x^6+x^7+x^8+x^9+x^10+x^11  +  x^8+x^9+x^10+x^11+x^12+x^13+x^14+x^15)

=1+x+x^2+x^3+2*x^4+2*x^5+2*x^6+2*x^7+2*x^8+2*x^9+2*x^10+2*x^11+x^12+x^13+x^14+x^15


由于不太熟悉怎么插入数学公式,搞的上面的式子看起来有点难受……以上过程也就是不断的计算前 i 个多项式相乘的结果。最后得到的式子中 m*x^n 就表示可以有m种方式称出质量为n的物品。一共有x~x^15个不同的质量,也就是最多能称出15中不同质量的物品。


下面先给出模板代码,并讲解代码的含义:


#define MAXN 55
int a[MAXN],b[MAXN];
int s[MAXN],e[MAXN],v[MAXN];

void mu(int n)
{ //n为因子个数 
	int i,j,k;
	memset(a,0,sizeof(a));
	a[0]=1;
	for(i=1;i<=n;i++)
	{ //前i项相乘 
		memset(b,0,sizeof(b));
		//j为第i种物品可能的数量,j*v[i]即第i个括号中第j项的系数
		for(j=s[i];j<=e[i]&&j*v[i]<=MAXN;j++)
			for(k=0;k+j*v[i]<=MAXN;k++) //计算对前i-1项相乘的结果的第k项的系数产生的影响 
				b[k+j*v[i]]+=a[k];
		memcpy(a,b,sizeof(b)); //将b数组存回a数组 
	}	
}

以上代码中MAXN为结果可能生成的x的指数的最大值。

a数组存储最终结果,b数组存储中间结果
s[i] (start数组)为第i个变量的最小个数,一般都为0,e[i] (end数组)为第i个变量的最大个数
v[i]表示第i个未知量的取值,即x^v[i]
a[i]存储的是未知量 x^i 前面的系数


也就是a存储前i-1项的相乘结果,然后遍历第i项中的每一个变量,让其与a中的每一项相乘,将结果临时存储到b数组中,最后存回a数组。


例如:求不同个数的不同质量的砝码可以组成的质量为 i 的种类数
v[i]存第i种砝码质量,s[i]存第i种砝码最小的个数,e[i]存第i种砝码最大的个数,a[i]存可以组成的质量为i的种类数

最后给出个例题及我写的解析:HDU 1028

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值