题目大意
假设有$x_1$个字母A,$x_2$个字母B,$\ldots$,$x_{26}$个字母Z,同时假设字母A的价值为$1$,字母B的价值为$2$,$\ldots$,字母Z的价值为$26$。那么,对于给定的字母,可以找到多少价值$\le50$的单词呢?单词的价值就是组成一个单词的所有字母的价值之和,比如,单词ACM的价值是$1+3+14=18$,单词HDU的价值是$8+4+21=33$。(组成的单词与排列顺序无关,比如ACM与CMA认为是同一个单词)。
题目分析
因为无顺序影响,故考虑使用普通型生成函数。
暴力预处理生成函数,暴力卷积。
如果没事干写FFT也是可以的。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include<algorithm> #include<iostream> #include<iomanip> #include<cstring> #include<cstdlib> #include<climits> #include<vector> #include<cstdio> #include<cmath> #include<queue> using namespace std;
inline const int Get_Int() { int num=0,bj=1; char x=getchar(); while(x<'0'||x>'9') { if(x=='-')bj=-1; x=getchar(); } while(x>='0'&&x<='9') { num=num*10+x-'0'; x=getchar(); } return num*bj; }
int now[55],pre[55],a[55];
int main() { int t=Get_Int(); while(t--) { memset(now,0,sizeof(now)); memset(pre,0,sizeof(pre)); pre[0]=1; for(int i=1; i<=26; i++) { int x=Get_Int(); memset(a,0,sizeof(a)); a[0]=1; for(int j=0; j<=min(50,i*x); j+=i)a[j]=1; for(int j=0; j<=50; j++) for(int k=0; k<=min(i*x,50-j); k++) now[j+k]+=pre[j]*a[k]; memcpy(pre,now,sizeof(pre)); memset(now,0,sizeof(now)); } int ans=0; for(int i=1; i<=50; i++)ans+=pre[i]; printf("%d\n",ans); } return 0; }
|