题意:2n个人排队上厕所,有两个厕所,一个男女都可以上,一个只有女的可以上,每个人上厕所都只有一分钟,你可以调整这些人的顺序,每个的怒气值为有多少后面的人排到自己前面了。求可以n分钟上完厕所的情况中,怒气最大的最小。
这题看半天没思路,只能看题解。
首先厕所一分钟都不能停,要么男女一起上两个厕所,要么女女一起,发现女生随意和谁匹配,考虑怎样满足男生的匹配。如果从前往后模拟看的话,我们遇到男生后面找不到女生的情况,就无从下手,因为前面的都已经匹配了。我们可以从后往前看,有一个规则就是男的不能比女的多两个以上,这个后缀开头一定是男生(如果不是往后找一定有),因为如果多一个,这个男生还可以和前面的女生匹配;但多了两个的话,如果和前面匹配掉一个,剩下还是多一个男生,但他已经不能和前面匹配了。如果和后面的匹配,就跟不行了,因为本来女生就少了。
所以记录后缀和,男生为1,女生为-1,如果当前位置后缀和为x,那么我们需要移走x - 1个男生,留下一个男生可以和前面匹配(如果有解一定可以匹配),那么有x-1个移到前面去了,就有人有x - 1的怒气值,所有情况求最大值即可(因为这样操作已经最优了,我们要求最大的最小,也就是每个后缀的最优解中最大的)。
还有一个问题是他的输入意思时一段复制多份然后连起来,因为数据太大我们无法还原字符串,但每个位置后面的后缀和还是可以算的,那么我们只要求这个段里最大后缀值就行了,如果这段的一份的值总和大于0,那么可以假设k-1份,剩下一份我们单独对这个一份字符串求个最大后缀,然后加起来,这就是这个段可以拼出的最大后缀。如果小于0,直接加上最大后缀就行了。
点击查看代码
void solve() {i64 n, m;std::cin >> n >> m;std::string s;std::vector<i64> sum(m), max(m), k(m);for (int i = 0; i < m; ++ i) {std::string t;std::cin >> t >> k[i];for (int j = (int)t.size() - 1; j >= 0; -- j) {sum[i] += t[j] == 'M' ? 1 : -1;max[i] = std::max(max[i], sum[i]);}}i64 tot = 0, ans = 0;for (int i = m - 1; i >= 0; -- i) {if (sum[i] > 0) {ans = std::max(ans, tot + (k[i] - 1) * sum[i] + max[i] - 1);} else {ans = std::max(ans, tot + max[i] - 1);}tot += sum[i] * k[i];}if (tot >= 2) {std::cout << -1 << "\n";} else {std::cout << ans << "\n";}
}