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题)