http://acm.hdu.edu.cn/showproblem.php?pid=2082
每一个字母的价值固定,但数目不定。所以每个字母对应的表达式也不同,若第i个字母的个数为a[i],价值为i,那么它的母函数为(1+x^i+x^(2i)+.....+x^(a[i]*b[i]))。那么将i属于[1,26]的母函数相乘得到的x^m(1<=m<=50)的系数相加就是答案。
#include <stdio.h> #include <iostream> #include <map> #include <set> #include <stack> #include <vector> #include <math.h> #include <string.h> #include <queue> #include <string> #include <stdlib.h> #include <algorithm> #define LL long long #define _LL __int64 #define eps 1e-12 #define PI acos(-1.0) using namespace std; int c1[60],c2[60]; int a[30],b[30]; int main() { int n; scanf("%d",&n); while(n--) { for(int i = 1; i <= 26; i++) { cin >> a[i]; b[i] = i; } memset(c1,0,sizeof(c1)); memset(c2,0,sizeof(c2)); //对一个表达式初始化,即(1+x+x^2+....+x^(a[1]))。 for(int i = 0; i <= a[1]; i++) c1[i] = 1; for(int i = 2; i <= 26; i++) { for(int j = 0; j <= 50; j++) { for(int k = 0; k+j<=50 && k<=a[i]*b[i]; k += b[i]) //注意k <= a[i]*b[i]。 c2[k+j] += c1[j]; } for(int j = 0; j <= 50; j++) { c1[j] = c2[j]; c2[j] = 0; } } int sum = 0; for(int i = 1; i <= 50; i++) sum += c1[i]; cout << sum << endl; } return 0; }
当然可以用多重背包解决。设dp[i][v]表示将前i种物品恰好装入容量为v的背包的方案数,那么得到状态转移式dp[i][v] += dp[i-1][v-k*c[i]] ,(0 <= k <= a[i]),a[i]为第i种物品的个数。
#include <set> #include <stack> #include <vector> #include <math.h> #include <string.h> #include <queue> #include <string> #include <stdlib.h> #include <algorithm> #define LL long long #define _LL __int64 #define eps 1e-12 #define PI acos(-1.0) using namespace std; int dp[30][60]; int a[30]; int main() { int n; scanf("%d",&n); while(n--) { for(int i = 1; i <= 26; i++) cin >> a[i]; memset(dp,0,sizeof(dp)); dp[0][0] = 1; for(int i = 1; i <= 26; i++) { for(int j = 0; j <= a[i]; j++) { for(int v = i*j; v <= 50; v++) dp[i][v] += dp[i-1][v-i*j]; } } int sum = 0; for(int i = 1; i <= 50; i++) sum += dp[26][i]; cout << sum << endl; } return 0; }