选课时间(题目已修改,注意读题)
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2026 Accepted Submission(s): 1612
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
2
2 2
1 2
2 1
40 8
1 1
2 2
3 2
4 2
5 8
6 9
7 6
8 8
Sample Output
2
445
Author
xhd
Source
Recommend
lcy
现在以上面的第二种情况每种种类个数无限为例,给出模板:
我们来解释下上面标志的各个地方:(***********!!!重点!!!***********)
① 、首先对c1初始化,由第一个表达式(1+x+x^2+..x^n)初始化,把质量从0到n的所有砝码都初始化为1.
② 、 i从2到n遍历,这里i就是指第i个表达式,上面给出的第二种母函数关系式里,每一个括号括起来的就是一个表达式。
③、j 从0到n遍历,这里j就是(前面i個表达式累乘的表达式)里第j个变量,(这里感谢一下seagg朋友给我指出的错误,大家可以看下留言处的讨论)。如(1+x)(1+x^2)(1+x^3),j先指示的是1和x的系数,i=2执行完之后变为
(1+x+x^2+x^3)(1+x^3),这时候j应该指示的是合并后的第一个括号的四个变量的系数。④ 、 k表示的是第j个指数,所以k每次增i(因为第i个表达式的增量是i)。
⑤ 、把c2的值赋给c1,而把c2初始化为0,因为c2每次是从一个表达式中开始的。
初学者请阅读:http://www.wutianqi.com/?p=596
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=50; int c1[N],c2[N],score[10]; int main(){ //freopen("input.txt","r",stdin); int t,n,m; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m); for(int i=0;i<N;i++){ c1[i]=0; c2[i]=0; } memset(score,0,sizeof(score)); int a,b; for(int i=1;i<=m;i++){ scanf("%d%d",&a,&b); score[a]=b; } c1[0]=1; for(int i=1;i<=m;i++){ for(int j=0;j<=n;j++) for(int k=0;k<=score[i] && j+k*i<=n;k++) c2[j+k*i]+=c1[j]; for(int j=0;j<=n;j++){ c1[j]=c2[j]; c2[j]=0; } } printf("%d\n",c1[n]); } return 0; }