HDOJ--1171Big Event in HDU!母函数 HDOJ--1085Holding Bin-Laden Captive!!!母函数 HDOJ--1028Ignatius and the Princess III!!母函数 HDOJ--1398Square Coins!!母函数

普通型母函数

 定义:

对于任意数列a0,a1,a2…an 即用如下方法与一个函数联系起来:

~G(x) = a0 + a1x + a2x*2 + a3x^3 +….+ anx^n

则称G(x)是数列的生成函数(generating function)

例子:

比较典型的是:A(x) = (1+x)^n~C(n,0),C(n,1),C(n,2),C(n,3),…..,C(n,n)

指数型母函数

 生成函数是说,构造这么一个多项式函数g(x),使得xn次方系数为f(n)。 如:序列{0,12345…n}的生成函数为:f(x)=0+x+2x^2+3x^3+4x^4+…+nx^n

生成函数最绝妙的是,某些生成函数可以化简为一个很简单的函数。也就是说,不一定每个生成函数都是用一长串多项式来表示的。比如,这个函数f(n)=1 n当然是属于自然数的),它的生成函数就应该是g(x)=1+x+x^2+x^3+x^4+…(每一项都是一,即使n=0时也有x^0系数为1,所 以有常数项)。再仔细一看,这就是一个有无穷多项的等比数列求和嘛。如果-1<x<1,那么g(x)就等于1/(1-x)了。

举一个例子说明:

考虑这个问题:从二班选nMM出来有多少种选法。学过简单的排列与组合的同学都知道,答案就是C(4,n)。也就是说。从n=0开始,问题的答案分别是 1,4,6,4,1,0,0,0,…(从4MM中选出4个以上的人来方案数当然为0喽)。那么它的生成函数g(x)就应该是g(x)=1+4x+6x^2+4x^3+x^4。这不就是……二项式展开吗?于是,g(x)=(1+x)^4

 你或许应该知道,(1+x)^k=C(k,0)x^0+C(k,1)x^1+…+C(k,k)x^k;但你或许不知道,即使k为负数和小数的时候, 也有类似的结论: (1+x)^k=C(k,0)x^0+C(k,1)x^1+…+C(k,k)x^k+C(k,k+1)x^(k+1)+C(k,k+2)x^(k+2)+…

广义的组合数C(k,i)就等于

k(k-1)(k-2)(k-i+1)/i!,比如C(4,6)=4*3*2*1*0*(-1)/6!=0,再比如C(-1.4,2)=(-1.4)*(-2.4)/2!=1.68,k为整数时,所有i>k时的C(k,i)中分子都要“越过”0这一项,因此后面C(k,k+1),C(k,k+2)之类的都为0了,与我们的经典二项式定理结论相同;不同的是,牛顿二项式定理中的指数k可以是任意实数.

再举一个例子说明一些更复杂的生成函数。n=x1+x2+x3+…+xk有多少个非负整数解?这道题是学排列与组合的经典例题了。把每组解的每个数都 加1,就变成n+k=x1+x2+x3+…+xk的正整数解的个数了。教材上或许会出现这么一个难听的名字叫“隔板法”:把n+k个东西排成一排,在 n+k-1个空格中插入k-1个“隔板”。答案我们总是知道的,就是C(n+k-1,k-1)。它就等于C(n+k-1,n)。它关于n的生成函数是 g(x)=1/(1-x)^k。这个生成函数是怎么来的呢?其实,它就是(1-x)-k次方,.。事实上,我们有一个纯组合数学的 更简单的解释方法。因为我们刚才的几何级数1+x+x^2+x^3+x^4+…=1/(1-x),那么 (1+x+x^2+x^3+x^4+…)^k就等于1/(1-x)^k。仔细想想k(1+x+x^2+x^3+x^4+…)相乘是什么意思。 (1+x+x^2+x^3+x^4+…)^k的展开式中,n次项的系数就是我们的答案,因为它的这个系数是由原式完全展开后k个指数加起来恰好等于n的项合并起来得到的。

现在我们引用《组合数学》上暴经典的一个例题。很多书上都会有这类题。

我们要从苹果、香蕉、橘子和梨中拿一些水果出来,要求苹果只能拿偶数个,香蕉的个数要是5的倍数,橘子最多拿4个,梨要么不拿,要么只能拿一个。问按这样的要求拿n个水果的方案数。

结合刚才的k(1+x+x^2+x^3+x^4+…)相乘,我们也可以算出这个问题的生成函数。

引用内容

g(x)=(1+x^2+x^4+…)(1+x^5+x^10+..)(1+x+x^2+x^3+x^4)(1+x)

半都约掉了)

=(1-x)^(-2)=C(1,0)+C(2,1)x+C(3,2)x^2+C(4,3)x^3… (参见刚才对1/(1-x)^k的展开)

=1+2x+3x^2+4x^3+5x^4+….

于是,拿n个水果有n+1种方法。我们利用生成函数,完全使用代数手段得到了答案!

1/(1-x)=1+x+x^2+x^3+x^4+…是前面说过的。我们对这个式子等号两边同时求导数。于是,1/(1-x)^2=1+2x+3x^2+4x^3+5x^4+….;一步就得到了我们所需要的东西!不断地再求导数,我们同样可以得到刚才用复杂的牛顿二项式定理得到的那个结论。生成函数还有很多其它的处理手段,比如等式两边同时乘以、除以常数(相当于等式右边每一项乘以、除以常数),等式两边同时乘以、除以一个x(相当于等式右边的系数“移一位”),以及求微分积分等。

我们用两种方法得到了这样一个公式:1/(1-x)^n=1+C(n,1)x^1+C(n+1,2)x^2+C(n+2,3)x^3+…+C(n+k-1,k)x^k+…。这个公式非常有用,是把一个生成函数还原为数列的武器。而且还是核武器。

母函数(Generating function)详解

母函数可分为很多种,包括普通母函数指数母函数L级数贝尔级数狄利克雷级数。对每个序列都可以写出以上每个类型的一个母函数。构造母函数的目的一般是为了解决某个特定的问题,因此选用何种母函数视乎序列本身的特性和问题的类型。

这里先给出两句话,不懂的可以等看完这篇文章再回过头来看:“把组合问题的加法法则和幂级数的t的乘幂的相加对应起来”

“母函数的思想很简单—就是把离散数列和幂级数一一对应起来,把离散数列间的相互结合关系对应成为幂级数间的运算关系,最后由幂级数形式来确定离散数列的构造. “

我们首先来看下这个多项式乘法:

1.x的系数是a1,a2,…an 的单个组合的全体。

2. x2的系数是a1,a2,…a2的两个组合的全体。

………

n. xn的系数是a1,a2,….ann个组合的全体(只有1个)。

由此得到:如有图

 

 

 

 

 

母函数的定义:

对于序列a0a1a2,…构造一函数:

  :母函数详解

图三

称函数G(x)是序列a0a1a2,…的母函数

 G( x ) = a[0] + a[1] * x + a[2]* x^2 + ······


 

这里先给出2个例子,等会再结合题目分析:第一种:

1克、2克、3克、4克的砝码各一 枚,能称出哪几种重量?每种重量各有几种可能方案?

考虑用母函数来解决这个问题:

我们假设x表示砝码,x的指数表示砝码的重量,这样:

11克的砝码可以用函数1+x表示,

12克的砝码可以用函数1+x∧2表示,

13克的砝码可以用函数1+x∧3表示,

14克的砝码可以用函数1+x∧4表示,

我们拿1+x来说,前面已经说过,x表示砝码,x的指数表示砝码的重量!即这里就是一个质量为2的砝码,那么前面的1表示什么?按照上面的理解,1其实应该写为:1*x^0,1代表重量为2的砝码数量为0个。(理解!)

把组合问题的加法法则和幂级数的t的乘幂的相加对应起来

1+x表示了两种情况:1表示质量为2的砝码取0个的情况,x表示质量为2的砝码取1个的情况。这里说下各项系数的意义:

x前面的系数a表示相应质量的砝码取a个,而1就表示相应砝码取0个,这里可不能简单的认为相应砝码取0个就该是0*x(想下为何?结合数学式子)

所以,前面说的那句话的意义大家可以理解了吧?几种砝码的组合可以称重的情况,可以用以上几个函数的乘积表示:

(1+x)(1+x∧2)(1+x∧3)(1+x∧4)

= (1+x+x+x)(1+x+x+x)

=1+x+x+2x+2x+2x+2x+2x+x+x+x

从上面的函数知道:可称出从1克到10克,系数便是方案数。(!!!经典!!!)

例如右端有2x项,即称出5克的方案有25=3+2=4+1;同样,6=1+2+3=4+210=1+2+3+4

故称出6克的方案有2,称出10克的方案有

接着上面,接下来是第二种情况:求用1分、2分、3分的邮票贴出不同数值的方案数:

大家把这种情况和第一种比较有何区别?第一种每种是一个,而这里每种是无限的。

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

母函数详解

以展开后的x为例,其系数为4,即4拆分成123之和的拆分数为4

即 :4=1+1+1+1=1+1+2=1+3=2+2

这里再引出两个概念整数拆分和拆分数:

所谓整数拆分即把整数分解成若干整数的和(相当于把n个无区别的球放到n个无标志的盒子,盒子允许空,也允许放多于一个球)。

整数拆分成若干整数的和,办法不一,不同拆分法的总数叫做拆分数

现在以上面的第二种情况每种种类个数无限为例,给出模板

// Author: Tanky Woo

// 母函数详解

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

母函数详解

ci  dao ti wei  gei chu mei zhong fa ma you duo shao ge

[cpp]  view plain  copy
  1. #include <iostream>  
  2.   
  3. using namespace std;  
  4.   
  5. const int _max = 10001;  
  6.   
  7. // c1是保存各项质量砝码可以组合的数目  
  8.   
  9. // c2是中间量,保存每一次的情况  
  10.   
  11. int c1[_max], c2[_max];  
  12.   
  13. int main()  
  14.   
  15. //int n,i,j,k;  
  16.       
  17.     int nNum; //  
  18.       
  19.     int i, j, k;  
  20.       
  21.     while(cin >> nNum)  
  22.       
  23.     {  
  24.       
  25.         for(i=0; i<=nNum; ++i) // —- ①  
  26.           
  27.         {  
  28.           
  29.             c1[i] = 1;  
  30.           
  31.             c2[i] = 0;  
  32.           
  33.         }  
  34.           
  35.         for(i=2; i<=nNum; ++i) // —– ②// bie wang le i*i<num na dao ti  
  36.           
  37.         {  
  38.               
  39.             for(j=0; j<=nNum; ++j) // —– ③  
  40.               
  41.                 for(k=0; k+j<=nNum; k+=i) // —- ④//bie wang le k+=i*i na dao ti  
  42.                   
  43.                 {  
  44.                   
  45.                     c2[j+k] += c1[j];  
  46.                   
  47.                 }  
  48.               
  49.             for(j=0; j<=nNum; ++j) // —- ⑤  
  50.               
  51.             {  
  52.               
  53.                 c1[j] = c2[j];  
  54.               
  55.                 c2[j] = 0;  
  56.               
  57.             }  
  58.           
  59.         }  
  60.           
  61.         cout << c1[nNum] << endl;  
  62.       
  63.     }  
  64.       
  65.     return 0;  
  66.   
  67. }  


我们来解释下上面标志的各个地方:

  、首先对c1初始化,由第一个表达式(1+x+x2+..xn)初始化,把质量从0n的所有砝码都初始化为1.

 

  、 i2n遍历,这里i就是指第i个表达式,上面给出的第二种母函数关系式里,每一个括号括起来的就是一个表达式。

 

 

0n遍历,这里j就是只一个表达式里第j个变量,比如在第二个表达式里:(1+x2+x4….)里,第j个就是x2*j.

 

  k表示的是第j个指数,所以k每次增i(因为第i个表达式的增量是i)。

 

  、把c2的值赋给c1,而把c2初始化为0,因为c2每次是从一个表达式中开始的

( 最外层,记录它正在与第几个多项式相乘。第二层,表示c1中的每一项,第三层表示后面被乘多项式中的每一项。)

以下两题是相似题注意区别

 

Holding Bin-Laden Captive!

此道题给出每种货币有多少个

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 8280    Accepted Submission(s): 3713

Problem Description

We all know that Bin-Laden is a notorious terrorist, and he has disappeared for a long time. But recently, it is reported that he hides in Hang Zhou of China!
“Oh, God! How terrible! ”

 

Don’t be so afraid, guys. Although he hides in a cave of Hang Zhou, he dares not to go out. Laden is so bored recent years that he fling himself into some math problems, and he said that if anyone can solve his problem, he will give himself up!
Ha-ha! Obviously, Laden is too proud of his intelligence! But, what is his problem?
“Given some Chinese Coins (硬币) (three kinds– 1, 2, 5), and their number is num_1, num_2 and num_5 respectively, please output the minimum value that you cannot pay with given coins.”
You, super ACMer, should solve the problem easily, and don’t forget to take $25000000 from Bush!

 

 

Input

Input contains multiple test cases. Each test case contains 3 positive integers num_1, num_2 and num_5 (0<=num_i<=1000). A test case containing 0 0 0 terminates the input and this test case is not to be processed.

 

 

Output

Output the minimum positive value that one cannot pay with given coins, one line for one case.

 

 

Sample Input

1 1 3
0 0 0

 

 

Sample Output

4

 

 

Author

lcy

/题意:给你面值是125的硬币的数量,要你求由这些硬币不能组成的最小的金额。。

下面给出3种方法;
//
方法1:很明显母函数
//
我这里一步一步的求。。
//
下面是我的一点理解。。如果叫你写由面值1,2,5的硬币所组成的金额的母函数
//Y=(1+x^2+x^3+x^4…+x^n1*1)*(1+x^2+x^4+x^6…x^n2*2)*(1+x^5+x^10+…x^n3*5)

 

 

[cpp]  view plain  copy
  1. #include <stdio.h>  
  2.   
  3. #include <string.h>  
  4.   
  5. #define MAX 10010  
  6.   
  7. int num[3];  
  8.   
  9. int val[3]={1,2,5};  
  10.   
  11. int n;  
  12.   
  13. int c1[MAX],c2[MAX];  
  14.   
  15. int main( )  
  16.   
  17. {  
  18.   
  19.     while(scanf("%d%d%d",&num[0],&num[1],&num[2]),num[0]||num[1]||num[2])  
  20.       
  21.     {  
  22.       
  23.         int i,j,k,t;  
  24.           
  25.         n=num[0]*1+num[1]*2+num[2]*5;// num[0]*val[0]+num[1]*val[1]+num[2]*val[3] budui  
  26.           
  27.         memset(c1,0,sizeof(c1));  
  28.           
  29.         memset(c2,0,sizeof(c2));  
  30.           
  31.         for( i=0;i<=num[0];i+=val[0])  
  32.           
  33.         {  
  34.           
  35.             c1[i]=1;  
  36.           
  37.         }  
  38.           
  39.         for( i=1;i<=2;i++)  
  40.           
  41.         {  
  42.           
  43.            
  44.           
  45.             for( j=0;j<=n;j++)  
  46.               
  47.             for( k=0;k<=num[i]*val[i]&&k+j<=n;k+=val[i])  
  48.               
  49.                 c2[j+k]+=c1[j];  
  50.               
  51.             for(t=0;t<=n;t++)  
  52.               
  53.             {  
  54.               
  55.                 c1[t]=c2[t];  
  56.               
  57.                 c2[t]=0;  
  58.               
  59.             }  
  60.           
  61.         }  
  62.           
  63.         for(i=0;i<=n+1;i++)  
  64.           
  65.             if(c1[i]==0)  
  66.               
  67.                
  68.               
  69.             {  
  70.               
  71.                 printf("%d\n",i);  
  72.               
  73.                 break;  
  74.               
  75.                
  76.               
  77.             }  
  78.       
  79.        
  80.       
  81.     }  
  82.       
  83.     return 0;   
  84.   
  85. }  


以上转至:http://blog.csdn.net/metalseed/article/details/8046656


另外一种母函数模板



母函数,又称生成函数,是ACM竞赛中经常使用的一种解题算法,常用来解决组合方面的题目。

本文讲解母函数,但不讲解该算法的基础理论。读者随便找一本组合数学教材便可找到相应的内容,或者直接在网上搜索一下。

母函数通常解决类似如下的问题:

给5张1元,4张2元,3张5元,要得到15元,有多少种组合?

某些时候会规定至少使用3张1元、1张2元、0张5元。

某些时候会规定有无数张1元、2元、5元。

……


解题过程

解题时,首先要写出表达式,通常是多项的乘积,每项由多个x^y组成。如(1+x+x^2)(1+x^4+x^8)(x^5+x^10+x^15)。

通用表达式为

(x^(v[0]*n1[0])+x^(v[0]*(n1[0]+1))+x^(v[0]*(n1[0]+2))+...+x^(v[0]*n2[0]))
(x^(v[1]*n1[1])+x^(v[1]*(n1[1]+1))+x^(v[1]*(n1[1]+2))+...+x^(v[1]*n2[1]))
...
(x^(v[K]*n1[K])+x^(v[K]*(n1[K]+1))+x^(v[K]*(n1[K]+2))+...+x^(v[K]*n2[K]))

K对应具体问题中物品的种类数。

v[i]表示该乘积表达式第i个因子的权重,对应于具体问题的每个物品的价值或者权重。

n1[i]表示该乘积表达式第i个因子的起始系数,对应于具体问题中的每个物品的最少个数,即最少要取多少个。

n2[i]表示该乘积表达式第i个因子的终止系数,对应于具体问题中的每个物品的最多个数,即最多要取多少个。

对于表达式(1+x+x^2)(x^8+x^10)(x^5+x^10+x^15+x^20),v[3]={1,2,5},n1[3]={0,4,1},n2[3]={2,5,4}。

解题的关键是要确定v、n1、n2数组的值。

通常n1都为0,但有时候不是这样。

n2有时候是无限大。

之后就实现表达式相乘,从第一个因子开始乘,直到最后一个为止。此处通常使用一个循环,循环变量为i。每次迭代的计算结果放在数组a中。计算结束后,a[i]表示权重i的组合数,对应具体问题的组合数。

循环内部是把每个因子的每个项和a中的每个项相乘,加到一个临时的数组b的对应位(这里有两层循环,加上最外层循环,总共有三层循环),之后就把b赋给a。

这些过程通常直接套用模板即可。

通用模板

下面我直接给出通用模板:

[cpp]  view plain  copy
  1. //为计算结果,b为中间结果。  
  2. int a[MAX],b[MAX];  
  3. //初始化a  
  4. memset(a,0,sizeof(a));  
  5. a[0]=1;  
  6. for (int i=1;i<=17;i++)//循环每个因子  
  7. {  
  8.     memset(b,0,sizeof(b));  
  9.     for (int j=n1[i];j<=n2[i]&&j*v[i]<=P;j++)//循环每个因子的每一项  
  10.         for (int k=0;k+j*v[i]<=P;k++)//循环a的每个项  
  11.             b[k+j*v[i]]+=a[k];//把结果加到对应位  
  12.     memcpy(a,b,sizeof(b));//b赋值给a  
  13. }  

P是可能的最大指数。拿钞票组合这题来说,如果要求15元有多少组合,那么P就是15;如果问最小的不能拼出的数值,那么P就是所有钱加起来的和。P有时可以直接省略。具体请看本文后面给出的例题。

如果n2是无穷,那么第二层循环条件j<=n2[i]可以去掉。


如何提高效率?

用一个last变量记录目前最大的指数,这样只需要在0..last上进行计算。

这里给出第二个模板:

[cpp]  view plain  copy
  1. //初始化a,因为有last,所以这里无需初始化其他位  
  2. a[0]=1;  
  3. int last=0;  
  4. for (int i=0;i<K;i++)  
  5. {  
  6.     int last2=min(last+n[i]*v[i],P);//计算下一次的last  
  7.     memset(b,0,sizeof(int)*(last2+1));//只清空b[0..last2]  
  8.     for (int j=n1[i];j<=n2[i]&&j*v[i]<=last2;j++)//这里是last2  
  9.         for (int k=0;k<=last&&k+j*v[i]<=last2;k++)//这里一个是last,一个是last2  
  10.             b[k+j*v[i]]+=a[k];  
  11.     memcpy(a,b,sizeof(int)*(last2+1));//b赋值给a,只赋值0..last2  
  12.     last=last2;//更新last  
  13. }  
转至: http://blog.csdn.net/xiaofei_it/article/details/17042651


附上第二种模板自己做的几个例题

HDOJ--1171Big Event in HDU!母函数




猜你喜欢

转载自blog.csdn.net/y_cnew/article/details/78585288