[luoguP10608]双人游戏
题目信息
原题链接
来源:[LGR-190]2024洛谷6月月赛II Div1 T1/Div2 T3
题意
长度为\(n\)的序列\(s\),其中只包含B
,W
和\(m\)个_
。给定长度为\(m\)的序列\(O=[\lang c_1,x_1\rang, \lang c_2,x_2\rang, \cdots,\lang c_m,x_m\rang](c_i\in\{\mathtt{R}, \mathtt{M}\},s_{x_i}=\text{'_'})\),表示玩家小\(c_i\)需要将\(s_{x_i}\)修改为B
或W
,且\(O\)对小R和小M公开。
小R希望极长同色连续段数(定义见原题)尽可能多,小M希望极长同色连续段数尽可能少,求经过序列\(O\)的操作后,极长同色连续段数的数量
赛时
Subtask害人不浅
在经历\(1.5h\)成功切下\(B2\)后,蒟蒻开始思考\(C\)
由于序列\(O\)对双方公开,所以对双方来说,即使需要按照\(O\)的顺序来操作,双方的操作也可以视为无序,因此我们可以将\(c_i\)直接填入\(s\)中。
假设\(O\)中只有\(\lang c_m,x_m \rang\)没有操作,若\(c_m=\text{R}\),则可能存在三种情况
- \(s_{x_i - 1} = s_{x_i + 1}\),此时选择与\(s_{x_i - 1}\)和\(s_{x_i + 1}\)相反的字符填入
- \(s_{x_i - 1} \ne s_{x_i + 1}\),此时选择与\(s_{x_i - 1}\)或\(s_{x_i + 1}\)相反的字符填入均可
- \(x_i = 1\)或\(x_i = n\),此时选择与\(s_{x_i}\)相邻字符的相反的字符填入即可
综上,我们发现,对于小R来说,选择与相邻字符相反的字符就是最优答案
同理,对小M来说,选择与相邻字符相反的字符就是最优答案
后来蒟蒻因为造出了\(m=n\)的hack数据,导致以为自己操作无序的结论证假,当场10pts跑路
赛后
事实上,操作无序的结论是正确的,只是因为蒟蒻没有深入考虑\(m=n\)的情况。
当\(m=n\)时,由于小\(c_1\)不管将\(s_{x_1}\)修改为什么,都不会影响输出的结果,因此,只需要将\(s_{x_1}\)任意修改为B
或W
即可
同时,也有可能出现__________B
的情况,此时,只需要从后向前再次扫描即可解决
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 200005;
char g[N];
int n, m;
char inv(char c){
return c == 'B' ? 'W' : 'B';
}
bool valid(char c){
return c == 'B' || c == 'W';
}
int main(){
scanf("%d%d", &n, &m);
scanf("%s", g + 1);
while (m -- ) {
char op[2];
int x;
scanf("%s%d", op, &x);
g[x] = *op;
if (m == n - 1) g[x] = 'B';
}
for (int i = 2; i <= n; i ++ ){
if (g[i] == 'B' || g[i] == 'W') continue;
if (g[i] == 'M' && valid(g[i - 1])) g[i] = g[i - 1];
else if (g[i] == 'R' && valid(g[i - 1])) g[i] = inv(g[i - 1]);
}
for (int i = n - 1; i; i -- ){
if (g[i] == 'B' || g[i] == 'W') continue;
if (g[i] == 'M' && valid(g[i + 1])) g[i] = g[i + 1];
else if (g[i] == 'R' && valid(g[i + 1])) g[i] = inv(g[i + 1]);
}
int ans = 0;
for (int i = 1; i <= n; i ++ )
if (g[i] != g[i - 1]) ans ++ ;
printf("%d\n", ans);
return 0;
}
UPDATE
2024.6.26:喜报,上洛谷了