母函数讲解

普通型母函数

 定义:

对于任意数列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

#include <iostream>

using namespace std;

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)
	
	{
	
		for(i=0; i<=nNum; ++i) // —- ①
		
		{
		
			c1[i] = 1;
		
			c2[i] = 0;
		
		}
		
		for(i=2; i<=nNum; ++i) // —– ②// bie wang le i*i<num na dao ti
		
		{
			
			for(j=0; j<=nNum; ++j) // —– ③
			
				for(k=0; k+j<=nNum; k+=i) // —- ④//bie wang le k+=i*i na dao ti
				
				{
				
					c2[j+k] += c1[j];
				
				}
			
			for(j=0; j<=nNum; ++j) // —- ⑤
			
			{
			
				c1[j] = c2[j];
			
				c2[j] = 0;
			
			}
		
		}
		
		cout << c1[nNum] << endl;
	
	}
	
	return 0;

}


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

  、首先对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)

 

 

#include <stdio.h>

#include <string.h>

#define MAX 10010

int num[3];

int val[3]={1,2,5};

int n;

int c1[MAX],c2[MAX];

int main( )

{

	while(scanf("%d%d%d",&num[0],&num[1],&num[2]),num[0]||num[1]||num[2])
	
	{
	
		int i,j,k,t;
		
		n=num[0]*1+num[1]*2+num[2]*5;// num[0]*val[0]+num[1]*val[1]+num[2]*val[3] budui
		
		memset(c1,0,sizeof(c1));
		
		memset(c2,0,sizeof(c2));
		
		for( i=0;i<=num[0];i+=val[0])
		
		{
		
			c1[i]=1;
		
		}
		
		for( i=1;i<=2;i++)
		
		{
		
		 
		
			for( j=0;j<=n;j++)
			
			for( k=0;k<=num[i]*val[i]&&k+j<=n;k+=val[i])
			
				c2[j+k]+=c1[j];
			
			for(t=0;t<=n;t++)
			
			{
			
				c1[t]=c2[t];
			
				c2[t]=0;
			
			}
		
		}
		
		for(i=0;i<=n+1;i++)
		
			if(c1[i]==0)
			
			 
			
			{
			
				printf("%d\n",i);
			
				break;
			
			 
			
			}
	
	 
	
	}
	
	return 0; 

}


Big Event in HDU

此道题既没给出每种种类也没给出不同种类的种类数

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 10995    Accepted Submission(s): 3827

 

Problem Description

Nowadays, we all know that Computer College is the biggest department in HDU. But, maybe you don’t know that Computer College had ever been split into Computer College and Software College in 2002.
The splitting is absolutely a big event in HDU! At the same time, it is a trouble thing too. All facilities must go halves. First, all facilities are assessed, and two facilities are thought to be same if they have the same value. It is assumed that there is N (0<N<1000) kinds of facilities (different value, different kinds).

 

 

Input

Input contains multiple test cases. Each test case starts with a number N (0 < N <= 50 — the total number of different facilities). The next N lines contain an integer V (0<V<=50 –value of facility) and an integer M (0<M<=100 –corresponding number of the facilities) each. You can assume that all V are different.
A test case starting with a negative integer terminates input and this test case is not to be processed.

 

 

Output

For each case, print one line containing two integers A and B which denote the value of Computer College and Software College will get respectively. A and B should be as equal as possible. At the same time, you should guarantee that A is not less than B.

 

 

Sample Input

2
10 1
20 1
3
10 1 
20 2
30 1
-1

 

 

Sample Output

20 10
40 40

题意:

给你n种物品,每种物品的价值,以及数量告诉你,
让你把它们尽可能的平分,但不能使输出的前一个数小于第二个,
小于0即停止执行

#include <stdio.h>

#include <string.h>

int main( )

{

	int m,n;
	
	int i,j,k,t;
	
	while(scanf("%d",&m)==1)
	
	{
		
		if(m<0) break;
		
		n=0;
		
		int val[m],num[m];//neng fang zhi shu zhu yue jian
		
		 
		
		for( i=0;i<m;i++)
		
		{
		
			scanf("%d%d",&val[i],&num[i]);
		
			n+=val[i]*num[i];
		
		}
		
		int c1[n+1],c2[n+1];
		
		memset(c1,0,sizeof(c1));
		
		memset(c2,0,sizeof(c2));
		
		for(i=0;i<=num[0]*val[0]&&i<=n;i+=val[0])
		
		{
		
			c1[i]=1;		 
		
		}
		
		for(i=1;i<=m-1;i++)
		
		{
		
			for(j=0;j<=n;j++)
			
			for(k=0;k<=num[i]*val[i]&&k+j<=n;k+=val[i])
			
				c2[j+k]+=c1[j];
			
			for(t=0;t<=n;t++)
			
			{
			
				c1[t]=c2[t];
			
				c2[t]=0; 
			
			}		 
		
		}
		
		for(i=n/2;i>0;i--)
		
		{
		
			if(c1[i]!=0)
		
			break;
		
		}
		
		printf("%d %d\n",n-i,i);
	
	}
	
	return 0;

}


 

L – Dividing

Crawling in process… Crawling failed Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

 

Description

Marsha and Bill own a collection of marbles. They want to split the collection among themselves so that both receive an equal share of the marbles. This would be easy if all the marbles had the same value, because then they could just split the collection in half. But unfortunately, some of the marbles are larger, or more beautiful than others. So, Marsha and Bill start by assigning a value, a natural number between one and six, to each marble. Now they want to divide the marbles so that each of them gets the same total value.
Unfortunately, they realize that it might be impossible to divide the marbles in this way (even if the total value of all marbles is even). For example, if there are one marble of value 1, one of value 3 and two of value 4, then they cannot be split into sets of equal value. So, they ask you to write a program that checks whether there is a fair partition of the marbles.
 

Input

Each line in the input describes one collection of marbles to be divided. The lines consist of six non-negative integers n1, n2, …, n6, where ni is the number of marbles of value i. So, the example from above would be described by the input-line “1 0 1 2 0 0”. The maximum total number of marbles will be 20000.

The last line of the input file will be “0 0 0 0 0 0”; do not process this line.

 

Output

For each colletcion, output “Collection #k:”, where k is the number of the test case, and then either “Can be divided.” or “Can’t be divided.”.

Output a blank line after each test case.

 

Sample Input

1 0 1 2 0 0
1 0 0 0 1 1
0 0 0 0 0 0
 

Sample Output

Collection #1:
Can’t be divided.
Collection #2:
Can be divided.
题意
 

有分别价值为1,2,3,4,5,6的6种物品,输入6个数字,表示相应价值的物品的数量,问一下能不能将物品分成两份,是两份的总价值相等,其中一个物品不能切开,只能分给其中的某一方,当输入六个0是(即没有物品了),这程序结束,总物品的总个数不超过20000

 
 
 

#include <stdio.h>
#include <string.h>
#define N 20000
int c[N];
int num[7];
int p;
int main( )
{
    int i,j,k,t=0;
    while(scanf("%d%d%d%d%d%d",&num[1],&num[2],&num[3],&num[4],&num[5],&num[6]),num[1]||num[2]||num[3]||num[4]||num[5]||num[6])
    {
    
     
      for(i=1;i<=6;i++)
     {
        num[i]%=10; //(取到最后发现对10取余就好了,多了感觉没有什么用!)
        
     }
     p=1*num[1]+2*num[2]+3*num[3]+4*num[4]+5*num[5]+6*num[6];
     memset(c,0,sizeof(c));
     printf("Collection #%d:\n",++t);
     if(p%2)
  
     {
         printf("Can’t be divided.\n");
       
      
     }  
      else{
             c[0]=1;
         p/=2;
         for( i=1;i<=6;i++)
         {
              for( j=p;j>=0;j--)
              for( k=1;k<=num[i]&&j+k*i<=p;k++)//从大到小       

             c[j+k*i]|=c[j];//(存在性的判断)
         }
         if(c[p])
         printf("Can be divided.\n");
         else
         printf("Can’t be divided.\n");
        
         }
         puts("");

    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值