https://codeforces.com/contest/1244/problem/F
题意:
给你一个由n个点围成的环,初始状态下环上每一个点都有黑或者白两种状态,此时要进行k次变换
每次变换,对于某个点,其颜色为这个点以及其左右两边的两个点上较多的颜色,用W表示白色,B表示黑色,则 BWB 这三个点中间的W下一次应该变为黑色
问进行k次变换之后每个点的颜色是什么。
1.假如有两个以上的点是相同的颜色,那么无论如何变换这两个点都不会变色,所以一开始可以将这样的段找出来作个标记
2.对于某段由相同颜色组成的段,每一次变换都会将段两端的点变为段的颜色
比如
BWBWWWBWBW
第一次: WBWWWWWBWB
第二次:BWWWWWWWBW
第三次:WWWWWWWWWB
第四次:WWWWWWWWWW
3.什么时候趋于稳定(如何变化都不会改变点的颜色),只有当换上所有点都属于任何一个段的时候
比如 BWWBBWWB,每个点都属于一个段,此时稳定
那么对于那些不属于段的点,我们计算出其距离最近段的距离,和k比较,就可以直到这个点最后是什么颜色了
怎么计算距离呢,顺着找一次,逆着找一次
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 2e5 + 7;
int dis[maxn], num[maxn], flag[maxn];
//dis:最近段距离 , num:颜色 flag:点是否属于一个段
int n, k, hav;
//hav:环中是否有段
char inp[maxn];
int main() {
memset(dis, INF, sizeof(dis));
cin >> n >> k;
scanf("%s", inp + 1);
for (int i = 1; i <= n; i++) {
if (inp[i] == 'B') num[i] = 1;
}
//构造flag数组
for (int i = 2; i <= n; i++) {
if (num[i] == num[i - 1])
flag[i] = flag[i - 1] = 1, hav = 1;
}
if (num[1] == num[n]) flag[1] = flag[n] = 1, hav = 1;
int near = 0;//near: 表示最近的段的下标
if (hav == 0)//假如没段,直接去结尾
goto to;
//顺着
for(int i=n;i;i--)//最开始的点最近的段可能在1的左边
if (flag[i] == 1) {
near = -i; //特别标记为负数,便于识别
break;
}
for (int i = 1; i <= n; i++) {
if (!flag[i]) {
if (near < 0) {
dis[i] = n + near + i;
}
else dis[i] = i - near;
}
else near = i;
}
//逆着
for(int i=1;i<=n;i++)
if (flag[i] == 1) {
near = -i;
break;
}
for (int i = n; i; i--) {
if (!flag[i]) {
if (near < 0) {
dis[i] = min(-near + n - i, dis[i]);
}
else dis[i] = min(near - i, dis[i]);
}
else near = i;
}
to: int times;
for (int i = 1; i <= n; i++) {
if (flag[i] == 1) putchar(inp[i]);
else {
times = min(k, dis[i]);
times %= 2;
if (times == 0) putchar(inp[i]);
else putchar((inp[i] == 'W' ? 'B' : 'W'));
}
}
return 0;
}