母函数


母函数又称生成函数。定义是给出序列:a0,a1,a2,.......ak,......,那么函数G(x)=a0+a1*x+a2*x2+......ak*xk称为序列a0,a1,a2,.......ak,......的母函数(即生成函数)。

题1:若有1克、2克、3克、4克的砝码各一 枚,能称出哪几种重量?各有几种可能方案?
构造母函数,如果用x的指数表示称出的重量,则:
1个1克的砝码可以用函数1+x表示,(前面的这个1表示1克的砝码个数为0)
1个2克的砝码可以用函数1+x2表示,
1个3克的砝码可以用函数1+x3表示,
1个4克的砝码可以用函数1+x4表示,
那么几种砝码的组合情况的用乘积表示有:(1+x)(1+x2)(1+x3)(1+x4)=1+x+x2+2x3+2x4+2x5+2x6+2x7+x8+x9+x10 ,系数即为方案数。

如果4种砝码的数量为a1,a2,a3,a4   

(1+x+x^2+x^3+.........x^a1)∗(1+x^2+x^4+x^6+.........x^2*cnt2)∗(1+x^3+x^6+x^9+............x^3*a3)*(1+x^4+x^8+x^12+.........x^4*a4)
例称出重量为6的物品:①、1,2,3;②、2,4两种方案。
========================================================================================================

例题2:求用1分、2分、3分的邮票贴出不同数值的方案数?

这个相对于上面的那个例子是:这个邮票可以重复。可知其生成函数为:G(x)=(1+x+x2+....)(1+x2+x4+....)(1+x3+x6+...),同理展开后其系数即为方案数。

==========================================================================================================================


例题3:整数分解

问题描述:把一个整数n划分成1到n的划分,例如3可以划分为1+1+1,1+2,3这三种划分,那么求n的划分数。

那么1可能出现,0,1,2,3,4,5,6...n次,而2可能出现0,1,2,3,.......n/2次,3可能出现0,1,2,3,4........n/3次等等。

(1+x+x^2+x^3+x^4+x^5+....)*(1+x^2+x^4+x^6+x^8+x^10+....)*(1+x^3+x^6+x^9+x^12....).....

母函数的基本代码模板

对于(#式)  (1+x+x^2+x^3+x^4+x^5+....)*(1+x^2+x^4+x^6+x^8+x^10+....)*(1+x^3+x^6+x^9+x^12....).....
第一个for给c1 和 c2 赋值 , 把上面#式的第一个括号(1+x+x^2+x^3+x^4+x^5+....)的系数给放在c1中,
从而再次计算从 # 的 第二个括号开始 , 所以 i 就是代表的# 式第几个括号,
而 用程序模拟手工计算 , 就是 先计算第一个括号 与 第二个括号 计算 , 把结果放到c2中,
在把结果与第三个括号计算 , 把结果放到c2中 , 在和第四个括号计算,........
c1[n]保存着Xn项前的系数,也就是n个(a1,...,an)组合数


/*//整数拆分模板
const int lmax=10000;
//c1是用来存放展开式的系数的,而c2则是用来计算时保存的,
//他是用下标来控制每一项的位置,比如 c2[3] 就是 x^3 的系数。 
//用c1保存,然后在计算时用c2来保存变化的值。 
int c1[lmax+1],c2[lmax+1];
int main()
{
            int n, i, j, k ;
           // 计算的方法还是模拟手动运算,一个括号一个括号的计算,
           // 从前往后 
           while ( cin>>n )

          {
              //处理第一个,对于 1+x+x^2+x^3+ 他们所有的系数都是 1 
              // 而 c2全部被初始化为0是因为以后要用到 c2[i] += x ; 
             for ( i=0; i<=n; i++ )//n为第一个式子的最大指数

              {
                c1[i]=1;
                c2[i]=0;
               }
    //第一层循环是一共有 n 个小括号,而刚才已经算过一个了,所以是从2 到 n 
       for (i=2; i<=n; i++)

       {
          // 第二层循环是把每一个小括号里面的每一项,都要与前一个
          //小括号里面的每一项计算。 
          for ( j=0; j<=n; j++ )
               for ( k=0; k+j<=n; k+=i )//此时还要加k<=这项括号里的最高项数

               {
                  // 合并同类项,他们的系数要加在一起,所以是加法。 
                    c2[ j+k] += c1[ j];
                 }
// 刷新一下数据,继续下一次计算,就是下一个括号里面的每一项。 
               for ( j=0; j<=n; j++ )
                       c1[j] = c2[j] ;
                memset(c2,0,sizeof(c2));
    }
          cout<<c1[n]<<endl;
        }
         return 0;
}



hdu 1028求整数划分的个数

#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
int c1[130],c2[130];
int main()
{
    int n;
    while(cin>>n)
    {
        memset(c2,0,sizeof(c2));
        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];
            memset(c2,0,sizeof(c2));
        }
        cout<<c1[n]<<endl;
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值