hdu 1085

Holding Bin-Laden Captive!

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


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
题解:求不能组成的最小金额,可以反向求能够组成那些金额? 关于数量的问题,运用母函数的知识。

普通型母函数

 定义:

对于任意数列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,那么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)

 关于母函数的题,看了别人的内容之后,认为就是用程序的方式来求解类似(1+x)(1+x^2)(1+x^3)(1+x^4);这种形式的式子对应的系数和它的指数。当然还有很多种母函数,如指数型,这里以普通型为例。
如果这样理解那么
1.“把组合问题的加法法则和幂级数的乘幂对应起来”

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

就可以稍微理解了。

代码:

#include
#include
#define Max 3
#define Max1 9000
int num[Max];
int value[Max] = {1, 2, 5};
int c1[Max1], c2[Max1];
int main() {
    int i, j, k, n;
    while(scanf("%d%d%d", &num[0], &num[1], &num[2]) != EOF) {
        if(!num[0] && !num[1] && !num[2])
            return 0;
        memset(c1, 0, sizeof(c1));
        memset(c2, 0, sizeof(c2));
        n = num[0] * value[0] + num[1] * value[1] + num[2] * value[2];

        for(i = 0; i <= value[0] * num[0]; i += value[0])
            c1[i] = 1;
        for(i = 1; i <= 2; i++) {
            for(j = 0; j <= n; j++)
                for(k = 0; k <= num[i] * value[i]; k += value[i]) {
                    c2[k+j] += c1[j];
                }
            for(k = 0; k <= n; k++) {
                c1[k] = c2[k];
                c2[k] = 0;
            }
        }

        for(i = 0; i <= n + 1; i++)
            if(c1[i] == 0) {
                printf("%d\n", i);
                break;
            }
    }
}




你可能感兴趣的:(母函数)