可以毫不犹豫的说这场CF是我有屎以来最失败的一场了,比赛期间交了两发A题都是Wrong answer on test 3,最终放弃回去(wan)睡(shou)觉(ji),然后愉快的挂了0而且获得了-108的Rating change,成功创下历史最大跌幅~
睡了一觉冷静了一下之后,开始思考为什么会出现这样的问题……至于这道题,原因还是从思路说吧。
题目不难,题意也不难理解,就是给你一些字符串,你要从中选出几个组成一篇文章,要求就是只出现两个字母并且文章要尽可能长。最后输出文章长度。
我也不是什么机智的人,没想到什么厉害的奇技淫巧,所以思路还是按照原始的题意走的。首先定义了一个结构体,用来表示一个字母出现的次数:
typedef struct { char ch; int n; }CH;
然后呢,只要再用一个vector,就能很简单的描述单个字符串中每个字符出现的次数了。为了方便,再写一个typedef:
typedef vectorWORD;
现在就可以开始处理题目了。首先是读取所有的字符串,把他转化成上面所写的描述方式,即出现了哪些字母,以及他们出现的次数:
int n; cin >> n; vectorwd(n); for (auto& w: wd) { string tmp; cin >> tmp; for (auto& c: tmp) { bool flag = false; for (auto& i: w) { if (c == i.ch) { i.n++; flag = true; break; } } if (!flag) { CH t; t.ch = c; t.n = 1; w.push_back(t); } } }
按照题意,出现三个或者更多字母的字符串是不可能被计入的,于是就把他们筛掉,留下那些只有两个或者一个字母出现过的字符串。判断一个单词中字母出现的的次数很简单,直接用vector的成员函数size()就可以解决。与此同时,把所有的留下的字符串中出现的字母统计一下,放入all中:
WORD all; vectorsel; for (auto& w: wd) { if (w.size() >= 3) continue; sel.push_back(w); for (auto& i: w) { bool flag = false; for (auto& c: all) if (c.ch == i.ch) { c.n += i.n; flag = true; break; } if (!flag) all.push_back(i); } }
经过这样一波处理后,sel内就保存了所有只出现过一个或两个字母的字符串,同时all里面统计了sel中所有的字符串中出现过的所有字母。
这样之后,答案所选的字符串毫无疑问就是all中抽出的一个或两个字母,问题也就在这出现了:比赛期间我没有考虑到所有字符串内都只有一个字母的情况!
int res = 0, tmp; for (int i = 0; i < all.size(); i++) { char c1 = all[i].ch; tmp = 0; //这个循环是比赛后看到错误原因了才补上的 for (auto& w: sel) { if (w.size() == 1 && w[0].ch == c1) tmp += w[0].n; } res = max(tmp, res); for (int j = i + 1; j < all.size(); j++) { char c2 = all[j].ch; tmp = 0; for (auto& w: sel) if (w.size() == 1 && (w[0].ch == c1 || w[0].ch == c2)) tmp += w[0].n; else if ((w[0].ch == c1 && w[1].ch == c2) || (w[1].ch == c1 && w[0].ch == c2)) tmp += w[0].n + w[1].n; res = max(tmp, res); } }
出了这个问题只要一组很简单的数据就能轻松爆掉我的代码:
1 a
答案显然是1,但是如果按照我原来的代码,直接就跳出循环了,愉快的输出了0……
王诗钧 11:34:07
·每次比赛后,即使做出来的题,也要试着看看别人的代码,看看他是不是用了一种比你更简洁的,bug更少的方式
·比如昨天的第一道题,你发现有bug,那么是不是你的思路可能不是很简洁,用了比较容易出bug的方法
王诗钧 11:35:22
·这样能够提高你以后写程序的正确率
·思维能力要通过思考题目以及看别人的题解获得
王诗钧 11:37:54
没有努力就可以超过别人的话,只会出现在别人太菜的情况下
于是我就去看了王诗钧的代码,理解后立马把自己的代码改写了试试,全文:
#includeusing namespace std; typedef struct { char ch; int n; }CH; typedef vector WORD; int main() { int n; int table[256][256]; for (auto &i: table) fill(i, i + 256, 0); cin >> n; vector wd(n); for (auto& w: wd) { string tmp; cin >> tmp; for (auto& c: tmp) { bool flag = false; for (auto& i: w) if (c == i.ch) { i.n++; flag = true; break; } if (!flag) w.push_back({c, 1}); } if (w.size() >= 3) continue; if (w.size() == 1) table[w[0].ch][0] += w[0].n; else table[min(w[0].ch, w[1].ch)][max(w[0].ch, w[1].ch)] += w[0].n + w[1].n; } int res = 0; for (int i = 'a'; i <= 'z'; i++) for (int j = i + 1; j <= 'z'; j++) res = max(res, table[i][j] + table[i][0] + table[j][0]); cout << res ; return 0; }
#待补充理解
不过就算是有了别人的方法,还是WA了一次……最后的两个for循环处z没有等号,然后也是愉快的一组数据爆掉代码……
2 z z
#待补充整体分析