USACO4.3 Letter Game【枚举·细节】
题意
这道题的题目描述让我好一阵蒙,简述一下题意吧:
给定一些字母的价值(如图所示),给出一个字符串(长度在$3$到$7$之间,可以出现重复的字母)和一个单词库。定义一个单词的价值就是它的字母的价值之和,一组单词的价值就是所有单词的价值之和,一组单词中的单词数量$>=1$,一组单词中的单词可以重复。要求用字符串中的字母拼成单词库中的一组单词,字符串中的字母不可以重复使用(如果字符串中有多个相同的字母,那么这个字母只能用出现的那么多次),求能够得到的单词组的最大价值并输出所有方案(按字典序)
分析
发现字符串的长度在$3$到$7$之间,单词的长度也在长度在$3$到$7$之间,说明一组单词最多有$2$个。
给出的词库大小是$40000$,但是字符串的只在$3$到$7$之间,也就是最多只有$7$种字母,所以有大量的单词实际上是不合法的,我们可以在输入的时候把它们去掉,只保存有用的单词。
更新一组里面只有一个单词的答案,然后两两枚举单词(一组),更新答案。
利用题目给出的单词库本身按字典序排的性质,有序地遍历就可以保证顺序(良心题目)
1 /* 2 ID: Starry21 3 LANG: C++ 4 TASK: lgame 5 */ 6 #include<cstdio> 7 #include<algorithm> 8 #include<vector> 9 #include<cstring> 10 #include<queue> 11 using namespace std; 12 #define ll long long 13 #define INF 0x3f3f3f3f 14 const int v[28]={2,5,4,4,1,6,5,5,1,7,6,3,5,2,3,5,7,2,1,2,4,6,6,7,5,7}; 15 char s[10]; 16 int cnt[30],c1[40005][30],c2[30]; 17 char dic[40005][10]; 18 int len[40005],val[40005]; 19 int n; 20 int ans[40005][2]; 21 int num,maxx=0; 22 void get(int i,int j) 23 { 24 int res=val[i]+val[j]; 25 if(res<maxx) return ; 26 if(res>maxx) 27 { 28 maxx=res; 29 num=0;//找到了更大的答案 重新来过 30 //ans[++num][0]=i,ans[num][1]=j;会在下面一个if里再算一次答案 31 } 32 if(res==maxx) 33 ans[++num][0]=i,ans[num][1]=j; 34 return ; 35 } 36 int main() 37 { 38 //freopen("lgame.in","r",stdin); 39 scanf("%s",s+1); 40 for(int i=1;i<=strlen(s+1);i++) 41 cnt[s[i]-'a']++; 42 //freopen("lgame.dict","r",stdin); 43 //freopen("lgame.out","w",stdout); 44 while(scanf("%s",s+1)!=EOF) 45 { 46 if(s[1]=='.') break; 47 n++; 48 memcpy(c1[n],cnt,sizeof(cnt)); 49 int tmp=0; 50 bool f=0; 51 for(int i=1;i<=strlen(s+1);i++) 52 { 53 c1[n][s[i]-'a']--; 54 if(c1[n][s[i]-'a']<0) 55 { 56 f=1; 57 n--; 58 break; 59 } 60 tmp+=v[s[i]-'a']; 61 } 62 if(f) continue; 63 strcpy(dic[n]+1,s+1); 64 //puts(dic[n]+1); 65 val[n]=tmp; 66 len[n]=strlen(s+1); 67 68 }//printf("%d\n",n); 69 for(int i=1;i<=n;i++) 70 { 71 //puts(dic[i]+1); 72 get(i,0); 73 for(int j=i+1;j<=n;j++)//字典序 1~i-1 get(j,i)不能保证第一个小 74 { 75 bool f=0; 76 memcpy(c2,c1[i],sizeof(c1[i])); 77 for(int k=1;k<=len[j];k++) 78 { 79 c2[dic[j][k]-'a']--; 80 if(c2[dic[j][k]-'a']<0) 81 { 82 f=1; 83 break; 84 } 85 } 86 if(f) continue; 87 get(i,j);//字典序 88 } 89 } 90 printf("%d\n",maxx); 91 for(int i=1;i<=num;i++) 92 { 93 printf("%s",dic[ans[i][0]]+1); 94 if(ans[i][1]) printf(" %s",dic[ans[i][1]]+1); 95 puts(""); 96 } 97 return 0; 98 } 99 /* 100 prmgroa 101 profile 102 program 103 prom 104 rag 105 ram 106 rom 107 . 108 */
转载请注明出处,有疑问欢迎探讨
博主邮箱 2775182058@qq.com