HDU 2082 找单词:http://acm.hdu.edu.cn/showproblem.php?pid=2082
题面:
2 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 2 6 2 10 2 2 5 6 1 0 2 7 0 2 2 7 5 10 6 10 2 10 6 1 9
7 379297
题目大意:
用字母去组合成单词,对于每个字母都有自己的价值,从A到Z价值分别从1到26,给定每个字母的个数,求总价值<=50的单词的个数。
题目分析:
此题为普通母函数的模板题,控制着指数在50以内,模拟多项式相乘之后记录多项式的系数,然后考虑到实际情况,x^0的系数不应被算在总数里面,因为由0个字母构不成任何单词。
下面来具体谈一下母函数的思想:
对于第一组样例,给出1个A,1个B,1个C,在组合字母时,对于A字母我们可以取1次,或者不取,由于其价值为1,所以列出 :(x^0+x^1) ;同理,对于字母B,我们也是可以取1次或者不取,由于其价值为2,所以列出 :(x^0+x^2);同理,对于字母C,其价值为3,所以我们列出 :(x^0+x^3)。之后三个多项式组合相乘,得到一个新的多项式。
而对于我们要求解的价值在50和50以内的字母,只需要把指数在1~50以内的指数的系数相加输出即可。
代码实现:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int a[30]; int a1[55],a2[55]; //a1[]用于存放多项式系数,指数为j,系数为a1[j] void Mhs() //模拟多项式相乘的母函数 { memset(a1,0,sizeof(a1)); memset(a2,0,sizeof(a2)); a1[0]=1; //x^0的系数为1 for(int i=1; i<=26; i++) //表示第几个多项式 { for(int j=0; j<=50; j++) //只计算指数<=50的,所以控制到50 { for(int k=0; k<=a[i] && k*i+j<=50; k++) { a2[k*i+j]+=a1[j]; //指数相加得j+k*i,而加多少取决于a1[j]的系数,因为被乘多项式的系数均为1 } } for(int j=0; j<=50; j++) { a1[j]=a2[j]; a2[j]=0; } } } int main() { int n; int sum; scanf("%d",&n); while(n--) { memset(a,0,sizeof(a)); sum=0; for(int i=1; i<=26; i++) { scanf("%d",&a[i]); } Mhs(); for(int i=1; i<=50; i++) //不计算x^0的系数是因为单词至少包含一个字母 { sum+=a1[i]; } printf("%d\n",sum); } return 0; }