luogu【P2753】[USACO4.3] letter_game

这个题。。。一开始看了很久题目(并且问了机房几个大佬)才明白题意。。
题意
大概是一开始给你一些字母出现的次数 你之后组成的单词(最多两个单词)每个字母出现次数 必须小于或等于标准(standard)的次数
其次是要满足你组成单词的 每个字符个数 * 该字符单个价值 最大。 如果有多解按字典序来。

自己的理解:
这个题目很良心 单词表可以去USACO官网上看。。都很短 而且给你的是按字典序来的 就不需要手动排序了
再其次楼下都讲了 很多单词存都不用存 一开始判断下就行了
对于这种东西 就应该用结构体存储 并且重载一些运算符 或者 成员函数 (因为很多操作是很重复的)
代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <algorithm>
 6 #include <cctype>
 7 #include <iostream>
 8 #define For(i, l, r) for(int i = (l); i <= (int)(r); ++i)
 9 #define Fordown(i, r, l) for(int i = (r); i >= (int)(l); --i)
10 #define Set(a, v) memset(a, v, sizeof(a))
11 using namespace std;
12
13 inline int read(){
14   int x = 0, fh = 1; char ch;
15   for(; !isdigit(ch); ch = getchar()) if (ch == ‘-‘) fh = -1;
16   for(; isdigit(ch); ch = getchar()) x = (x<<1) + (x<<3) + (ch^‘0‘);
17   return x * fh;
18 }
19
20 const int N = 40010;
21 const int score[26]={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};
22 //当然要把这个表打出来了。。但我太懒了。。copy了一下redbag大神的。。
23
24 struct node {
25     char str[101];
26     int dig[26]; //存储了每个单词出现的次数
27
28     void update () {
29         int n = strlen(str);
30         Set(dig, 0);
31         For (i, 0, n-1)
32             dig[str[i] - ‘a‘] ++;
33     } //更新每个字符出现的次数
34
35     int calc () {
36         int ans = 0;
37         For (i, 0, 25)
38             ans += dig[i] * score[i];
39         return ans;
40     } //计算这个单词的得分
41
42     bool operator > (const node &rhs) const {
43         For (i, 0, 25)
44             if (dig[i] > rhs.dig[i]) return true;
45         return false;
46     } //比较单词每个字母出现次数多少 如果多的话 则不满足题目要求
47
48     node operator + (const node &rhs) const {
49         node ans;
50         Set(ans.dig, 0);
51         For (i, 0, 25)
52             ans.dig[i] = dig[i] + rhs.dig[i];
53         return ans;
54     } //把两个单词出现次数加起来
55 };
56
57 node standard, word[N];
58 int cnt = 1;
59 struct ans_pair {
60     int word1, word2; //答案的词对 如果只有一个单词则第二个为0 这个存储的是单词的编号
61 };
62
63 #include <vector>
64 vector <ans_pair> lt; //听说 不定长数组 和 答案序列 更配哦 (滑稽)
65
66 int ans_num = 0;
67 int main(){
68     scanf ("%s", standard.str);
69     standard.update(); //把初始的标准更新
70     while (scanf ("%s", word[cnt].str) != EOF && word[cnt].str[0] != ‘.‘) {
71         word[cnt].update();
72         if (word[cnt] > standard) continue; //如果不满足要求就不能存储 让下一个输入的覆盖掉
73         ++cnt;
74     }
75     --cnt; //去掉最后一个‘.‘
76     For (i, 1, cnt)  {
77         int now_score = 0; //当前成绩
78         now_score = word[i].calc();
79         if (now_score > ans_num)
80         {ans_num = now_score; lt.clear(); lt.push_back((ans_pair) {i, 0} );} //比原来答案大 就更新一下
81         else if (now_score == ans_num) lt.push_back((ans_pair) {i, 0} ); //相同就放入vector
82
83         For (j, i+1, cnt) {
84             node new_word = word[i] + word[j]; //计算合并后单词的dig
85             if (new_word > standard ) continue; //不满足要求就继续找
86             now_score = new_word.calc(); //计算成绩
87             if (now_score > ans_num)  //同上
88             {ans_num = now_score; lt.clear(); lt.push_back((ans_pair) {i, j} );}
89             else if (now_score == ans_num) lt.push_back((ans_pair) {i, j} );
90         }
91     }
92
93     printf ("%d\n", ans_num);
94     For (i, 0, lt.size()-1) {
95         int fir = lt[i].word1, sec = lt[i].word2; //first 第一个单词 second 第二个单词
96         if (sec) printf ("%s %s\n", word[fir].str, word[sec].str);
97          else printf ("%s\n", word[fir].str); //如果只有一个单词 输出第一个单词就好了
98     }
99 }
时间: 2024-10-06 19:23:39

luogu【P2753】[USACO4.3] letter_game的相关文章

Luogu【模板】树状数组

https://www.luogu.org/problemnew/show/P3374 单点修改, 区间查询 1 //2018年2月18日17:58:16 2 #include <iostream> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 500001; 7 int n, m; 8 int a[N], c[N]; 9 10 inline int lowbit(int x){ 11 return x &

luogu 【P3377】 【模板】左偏树

左偏树模板... #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #include <cctype> #include <iostream> #define For(i, l, r) for(int i = (l); i <= (int)(r); ++i) #define For

Luogu【P1130】红牌(DP)

欧拉 本蒟蒻第一个自己想出来的DP题 请移步题目链接 调了半天.i从1到n,j从1到m. f[i][j]表示的是第i道工序在第j个小组办完所花的最短时间. 因为要用到上一个状态,而上一个状态要么是同一小组,要么是上一个小组 所以j的做法跟题目是反着的 so转移方程 f[i][j]=min(f[i-1][j],f[i-1][j==1?n:j-1]); f[i][j]+=mp[j][i]; 然后就找到完成所有工序耗时最短的组就行啦 #include<cstdio> #include<cstd

Luogu【P2904】跨河(DP)

题目链接在这里 此题DP.用一个前缀和一样的东西,把载i个奶牛的时间求出来,然后DP代码如下: for(int i=1;i<=n;++i){ f[i]=que[i]; for(int j=0;j<i;++j) f[i]=min(f[i],f[j]+que[i-j]); } 这句话的意思是说,先载i头奶牛,然后从载0头到载i-1头寻找,看有没有更优解.如果有,那么更新. 最后输出的时候输出DP[n]-m,因为最后FJ是不用再回对岸的 放上代码 #include<cstdio> #in

Luogu【P1901】发射站(单调栈)

题目链接 题目说明比自己矮的塔收不到自己的能量,摆明了就是单调栈呗. 把比自己矮的全都从栈里弹出去,于是碰到第一个比自己高的.让他接受自己发射的能量. 当然由于发射站发射的能量有两个方向,所以正反两遍. 然后 放代码. #include<cstdio> #include<cstdlib> #include<cctype> using namespace std; long long ans; inline long long max(long long a,long l

luogu【P1144】最短路计数

原题入口 这道题 一道有关于最短路的图论问题. 要求从1开始求解最短路的条数. 这个题十分有趣,首先,跑裸的spfa(或者dijkstra)算出从1开始的最短路的长度. 再其次,计数的话,可以用记忆化搜索(相当于DAG dp)我们现在所遍历的路径长度要刚好是最短路的长度. (这个程序中会有体现的) 这个题我前面一直在TLE,就是没有用记忆化,暴力去找路径.(第一遍还因为没算空间MLE..TAT) 后来优化后 时间效率挺不错.(500多ms) 下面上代码: 1 #include <bits/std

luogu【P3387】【模板】缩点

原题入口 PS:这个题数据是由Hany01大大出出来的 %%% 这个题显然是一道强联通+DAGdp的题 (题目背景有= =) 缩点的原因就是:不缩会一直在一个地方绕圈圈 而且不能进行后面的DAPdp 而且给你的所有点权全是正的 我在这用的是Tarjan(因为他发明算法太多了233) 这个dp方程比较容易找 令dp[u] 表示 缩点后 第u个强联通分量为起点的路径上点和的最大值 所以有 dp[u] = max{dp[v]} + val[u]  (这里v是指u出发可以到达的点) 由于是DAGdp 所

数组splay ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) #include <cstdio> #define Max 100005 #define Inline __attri\ bute__( ( optimize( "-O2" ) ) ) Inline void read (int &now) { now = 0; register char word = getchar (); bool temp = false; while (wor

luogu P3808 【模板】AC自动机(简单版)

二次联通门 : luogu P3808 [模板]AC自动机(简单版) /* luogu P3808 [模板]AC自动机(简单版) 手速越来越快了 10分钟一个AC自动机 一遍过编译 + 一边AC 感觉不错 我也就做做板子题了.. */ #include <iostream> #include <cstring> #include <cstdio> #include <queue> #define Max 1000009 void read (int &