CodeForces Global Round 11 B. Chess Cheater 贪心,处理技巧
CodeForces Global Round 11 B. Chess Cheater 贪心,处理技巧
题意
有一段\(WL\)序列表示输赢,若是\(W\)则加一分,若前一个是\(W\)则额外加一分
现有\(K\)次操作可以把\(L\)变成\(W\),问最大的分数是多少
\[1\leq n\leq 10^5\\
0\leq k \leq n
\]
分析
显然我们需要修改\(L\)来加分,如果没有“额外”的规则,那么加在哪里都一样,有了规则后,加入一段\(W\)后就有了三种可能:
\[2 \times k - 1\\
2 \times k\\
2\times k + 1
\]
我们自然会贪心的选择最好的策略。
发现如果是第三种可能,每加入一段后就会额外多1分,那么我们当然希望第三种越多越好
于是可以对每个\(L\)区间按长度排序,贪心选择长度短的区间。
其他可能就是前面或者最后连续的一段\(L\),处理方法就是初始化为\(cnt\)一个大于\(k\)的数。这样就一定会被排序到最后面。、
最后连续的\(L\)只需要把剩下的\(2\times k\)加入答案即可(具体见代码),因为最后总可以对答案取一个\(max\)
代码
char s[100005];
void solve() {
int n = readint();
int k = readint();
scanf("%s", s);
vector<int> v;
int cnt = k + 5;
int res = 0;
for (int i = 0; i < n; i++) {
if (s[i] == 'W') {
if (i && s[i - 1] == 'W') res += 2;
else res++;
}
else cnt++;
}
cnt = k + 5;
for (int i = 0; i < n; i++) {
if (s[i] != 'L') v.push_back(cnt), cnt = 0;
//else if (i == n - 1) {
// if (s[i] == 'L') cnt++;
// v.push_back(cnt);
//}
else cnt++;
}
if (cnt == 5 + k + n) {
printf("%d\n", max(0, 2 * k - 1));
return;
}
sort(v.begin(), v.end(), greater<int>{});
while (!v.empty() && v.back() == 0) v.pop_back();
reverse(v.begin(), v.end());
for (int i = 0; i < v.size() && k > 0 ; i++) {
if (k >= v[i]) k -= v[i], res += 2 * v[i] + 1;
}
res += 2 * k;
res = min(res, 2 * n - 1);
Put(res);
puts("");
}
int main() {
int T = readint();
while (T--)
solve();
}