母函数

来源:互联网 发布:sqlserver触发器语法 编辑:程序博客网 时间:2024/05/04 13:50

http://acm.hdu.edu.cn/showproblem.php?pid=2079

选课时间(题目已修改,注意读题)

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2352    Accepted Submission(s): 1872


Problem Description
又到了选课的时间了,xhd看着选课表发呆,为了想让下一学期好过点,他想知道学n个学分共有多少组合。你来帮帮他吧。(xhd认为一样学分的课没区别)
 

Input
输入数据的第一行是一个数据T,表示有T组数据。
每组数据的第一行是两个整数n(1 <= n <= 40),k(1 <= k <= 8)。
接着有k行,每行有两个整数a(1 <= a <= 8),b(1 <= b <= 10),表示学分为a的课有b门。
 

Output
对于每组输入数据,输出一个整数,表示学n个学分的组合数。
 

Sample Input
22 21 22 140 81 12 23 24 25 86 97 68 8
 

Sample Output
2445
 

Author
xhd
 

Source
ACM程序设计期末考试_热身赛(感谢 xhd & 8600)
 

Recommend
lcy


这道题,一开始看到的时候,第一感觉想用的是回朔,原来发现还有母函数的解法(母函数今天是第一次听说,
长见识了,ACM的好处啊),而且母函数还有固定的模板,又长见识了,母函数用的是组合与乘幂对应的方式,
求解的是一个多项式的系数与指数的关系,(aX^0+cX^1+dX^2.....)(aX^0+cX^1+dX^2.....)(aX^0+cX^1+dX^2.....)..
第一感觉就是用三层循环解决,最外层循环是控制()乘法的次数,比如有3个括号就应该乘2次,外循环唯一的
用处就是控制循环次数。内两层循环的用处就是求两个括号的乘积,我们需要的aX^b,这种形式的(a,b)数对,
有什么办法可以存储这样的数对呢?没错,(index,A[index]),用一个一维数组即可。还有一些细节,比如,两个()
相乘,其中我们知道一个()的界,因为此时最外层循环的指针直指向这个(),但是,另外一个()的指数界并不确定,
所以,只需要取<=CreditSum即可,因为再大也没有意义了,我们要求的是A[CreditSum].具体代码中体会:
#include <iostream>using namespace std;int main (){int T;cin >> T;while ( T-- ){int Credit[9];int SubjectSum[9];int num1[41]={0};int num2[41]={0};int CreditSum,Len;cin >> CreditSum >> Len;for ( int i = 1; i<= Len; ++ i ){cin >> Credit[i] >> SubjectSum[i]; } for ( int i = 0; i*Credit[1] <= SubjectSum[1]; ++ i ){//对于1+x+x^2+x^3+ 他们相应位的系数是1 // 而num2全部被初始化为0是因为以后要用到num2 += x ; num1[i*Credit[1]] = 1;num2[i*Credit[1]] = 0; }//最外层循环的唯一目的是控制Len-1次重复,因为有Len个()需要相乘Len-1次for ( int i = 2; i <= Len; ++ i ){//只需要处理CreditSum以内的系数即可,虽然总和可能超过CreditSum,//但是我的们的目标是num1[CreditSum]//这两层循环的功能就是求两个()的乘积系数//这里之所以用一个宽范的界CreditSum,是因为我们无法像下面的S//ubjectSum一样确定准确界//两个()相乘,只能确定一个()的准确界for ( int j = 0; j <= CreditSum; ++ j ) {//只计数到CreditSum就停因为num1[index]的index是指数,只需要=n,//则num1[n]就是它的系数for ( int k = 0; k <= SubjectSum[i] && k * Credit[i] + j <= CreditSum; ++ k ){//num1是上一次两个()相乘的结果//合并同类项,这里有点难理解,num2[]的内容有可能是{0,0,4,0,3},//说明这是x^2+3x^4//假设num1的内容是{0,1,3,0,2},说明x+3x^2+2x^4,合并同类项之后//是x+7x^2+5x^4//所以是{0,1,7,0,5}//c[i][j] =c[i][j] + xisu(x[i]*x[j]),c表示系数,x[i]表示真实数.//x[i]*x[j]的幂就是i+j了//下面可以写成xisu{cX^(k * Credit[i] + j)} =xisu{ cX^(k * Credit[i] + j) } + xisu //{ aX^j * bX^(k*Credit[i]) }//则有c=c+(a*b),因为X^(k*Credit[i])的系数b==1恒成立,可以省略掉//num2[k*Credit[i] + j]表示X^(k*Credit[i]) * X^j的系数num2[ k * Credit[i] + j ] += num1[j]; //写上*1也可以.} } for ( int j = 0; j <= CreditSum; ++ j ){num1[j] = num2[j]; //复制指数到num1中num2[j] = 0;//重置临时变量}}cout << num1[CreditSum] << endl;}return 0; }

Holding Bin-Laden Captive!

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


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 30 0 0
 

Sample Output
4
 

Author
lcy


HDU1085和上面的题目几乎一样,而且做了简化,上面的学分和这里的硬币币值对应,课的门数和这里的硬币数量对应,其余的思路完全一样.只是上面的需要凑出的总学分是给定的,下面的需要自定义一个上限.
#include<stdio.h>#include<algorithm>int num1[10010],num2[10010],coins[4]={0,1,2,5},num[4];void MuFunction(int l,int m,int n){int i,j,k,max;num[1]=l,num[2]=m,num[3]=n;max=num[1]+num[2]*2+num[3]*5;memset(num1,0,sizeof(num1));memset(num2,0,sizeof(num2));for( i=0;i<=num[1];++i)//初始化第一个括号的系数num1[i]=1;for(i=2;i<=3;++i)//有(3种硬币)3个括号要相乘2次{for(j=0;j<=max;++j)//这两层循环是计算两个括号乘积{for( k=0;k<=coins[i]*num[i] && k+j<=max;k += coins[i]){num2[k+j]+=num1[j];}}for(j=0;j<=max;++j){num1[j]=num2[j];num2[j]=0;}}for(i=1;;++i)//中间的条件省去应该可以ac,还真AC了,哈哈{if( num1[i] == 0){printf("%d\n",i);break;}}}int main(){int l,m,r;while(scanf("%d%d%d",&l,&m,&r)!=EOF && !(l==0&&m==0&&r==0)){MuFunction(l,m,r);}}
类似用母函数的经典题目还有HDU1398,而且一样是操作硬币.

Square Coins

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


Problem Description
People in Silverland use square coins. Not only they have square shapes but also their values are square numbers. Coins with values of all square numbers up to 289 (=17^2), i.e., 1-credit coins, 4-credit coins, 9-credit coins, ..., and 289-credit coins, are available in Silverland. 
There are four combinations of coins to pay ten credits: 

ten 1-credit coins,
one 4-credit coin and six 1-credit coins,
two 4-credit coins and two 1-credit coins, and
one 9-credit coin and one 1-credit coin. 

Your mission is to count the number of ways to pay a given amount using coins of Silverland.
 

Input
The input consists of lines each containing an integer meaning an amount to be paid, followed by a line containing a zero. You may assume that all the amounts are positive and less than 300.
 

Output
For each of the given amount, one line containing a single integer representing the number of combinations of coins should be output. No other characters should appear in the output. 
 

Sample Input
210300
 

Sample Output
1427
 

Source
Asia 1999, Kyoto (Japan)
 

Recommend
Ignatius.L
 
思路也是和上面的差不多,都是同样的模板.
#include<stdio.h>int num1[301],num2[301];void MuFunction(int n){int i,j,k;for( i=0;i<=n;++i)//初始化每一个括号的系数{num1[i]=1;num2[i]=0;}for( i=2;i<=17;++i)//有17个括号,需要计算16次{for( j=0;j<=n;++j){for( k=0;k+j<=n;k+=i*i){num2[j+k] += num1[j]; //{j}(i*i系数恒为1)}}for(int i=0;i<=n;++i){num1[i]=num2[i];num2[i]=0;}}printf("%d\n",num1[n]);}int main(){int n;while(scanf("%d",&n)!=EOF && n!=0){MuFunction(n);}}






原创粉丝点击