母函数(生成函数)

http://www.wutianqi.com/?p=596


ACM中常用的母函数大致分为两类,第一类是普通型,第二种是指数型。两种都在上述大牛的博客中有讨论。对于第二种指数型可参考hdu2065

#include <iostream>
using namespace std;
// Author: Tanky Woo
// www.wutianqi.com
const int _max = 10001; 
// c1是对于每一种给定的质量,一共用多少种组合数。
// c2是中间量,每次计算过一个表达式后要更新一次
int c1[_max], c2[_max];   
int main()
{	//int n,i,j,k;
	int nNum;   // 
	int i, j, k;
?
	while(cin >> nNum)
	{
		memset(c2,0,sizeof(c2)); 
		for(i=0; i<=nNum; ++i)   // ---- ①
		{
			c1[i] = 1;
		}
		for(i=2; i<=nNum; ++i)   // ----- ②
		{
?
			for(j=0; j<=nNum; ++j)   // ----- ③
				for(k=0; k+j<=nNum; k+=i)  // ---- ④
				{
					c2[j+k] += c1[j];
				}
			for(j=0; j<=nNum; ++j)     // ---- ⑤
			{
				c1[j] = c2[j];
				c2[j] = 0;
			}
		}
		cout << c1[nNum] << endl;
	}
	return 0;
}


主要对模板进行解释。

该模板公式可表示为: (1 + x^1 + x^2 + x^3 ....)*(1+ x^2 + x^4 +....)*(1+ x^3 + x^6 +....)

我们的任务就是模仿上式的展开。

①  首先c2数组必须清空为0,它的作用后边再讲。 这里是根据第一个表达式进行赋值,因为第一个表达式的步长为1,所以i每次加1,赋值成1是因为假如只有这一个表达式,那么它组成每种给定质量的情况都是1。

② 这里的i实际上表示的是步长,同时也指的是第二个表达式。比如说第一个表达式步长为1,第二个步长为2,第三个步长为3,所以i每次加1. 遍历到nNum是因为,当步长大于nNum时,x的指数一定大于nNum。

③ 我们把一个多个表达式相乘的问题,分解成了两个两个相乘的问题,即第一次是第一个表达式和第二个表达式相乘,它们的结果是一个新的表达式,我们暂且叫它temp,那么下一次我们要做的就是拿temp和第三个表达式相乘。  而这里的j指的就是前一个表达式各个项的指数,比如对于第二个表达式来说,第一项的指数是0,第二项的指数是2,第三项的指数是4。

④  k是指后一个表达式中各个项的系数。  所以j+k就是对应两项相乘后等到的项的系数。c2默认值是0,表示对于每个给定的质量,现在可以组成的情况都是0种,然后不断的加c1[j] 这里有点难理解,我也说不清楚。

⑤ 将中间变量的值赋给最后的保存结果的数组。 然后更新c2以进行下一次的记录。


上述模板只是对于每种质量的砝码个数无限的情况下,对于有限砝码的情况请见大神博客里面的题(尤其是3,4题)


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值