题目的字面意思:
就是说给出了一个环,然后对于每一个位置i判断他的左右邻居中白色多还是黑色多,哪个多,这个i就变成什么颜色。一次循环称为一次操作,然后问在k次操作之后,这个环是什么样子。
然后环的个数是2e5,k的个数是1e9
看到数据之后,就可以明白,暴力一定是不行的。(废话一句)
然后先给出两个定理:
1、
对于BWWB这样的串,一定是不会再产生任何的变化了,那么我们就可以总结出,如果i位置的左右任意一个位置有一个和他相同,那么i就不会再变了。
2、
如果位置i在第x次操作之后,不会再变化了(参考1),那么他左右的元素一定是在x+1轮不需要再变化了或者左右元素在这之前就已经不需要变化了。
证明方式如下,对于任意一个还在变化的位置来说,左右元素一定和他不一样(类似与010或者101),那么位置i发生变化之后,一定会影响他左右的还在变化的位置,也就是说左右位置一定会在下一轮的操作变成不需要变化的。证明结束。
详细的可以看代码,给了注释。
1 #include <stdio.h> 2 #include <queue> 3 using namespace std; 4 char s[200009]; 5 //预处理,就是可以快速的访问左右邻居,没啥好说 6 #define li (i-1+len)%len 7 #define ri (i+1)%len 8 #define lnow (now-1+len)%len 9 #define rnow (now+1)%len 10 //vis 数组 用来表示在 i 位置的元素什么时候开始不变化了 11 int vis[200009]; 12 int main() 13 { 14 queue <int> q; 15 int len, k, now; 16 scanf("%d %d %s", &len, &k, s); 17 for(int i = 0; i < len; i++) 18 { 19 vis[i] = -1; // 初始化 i 为 -1 表示 一直在变化 20 if(s[li]==s[i]||s[i]==s[ri]) // 说明 i 位置从一开始是就是不需要变化的 21 { 22 vis[i] = 0; 23 q.push(i); 24 } 25 } 26 while(!q.empty()) 27 { 28 now = q.front(); q.pop(); 29 if(vis[lnow]==-1) // 只有当前的左右邻居还没有被处理掉的时候才需要 30 { 31 vis[lnow] = vis[now] + 1; 32 q.push(lnow); 33 } 34 if(vis[rnow]==-1) 35 { 36 vis[rnow] = vis[now] + 1; 37 q.push(rnow); 38 } 39 } 40 for(int i = 0; i < len; i++) 41 if(vis[i]==-1) // 如果一直在变化 那么就是根据变化次数进行一个判断 42 { 43 if(k&1) printf("%c", 'W'+'B'-s[i]); //这个写法就很巧妙,多看dalao题解还是有好处啊 44 else printf("%c", s[i]); 45 }else{ 46 //这里需要对vis (不需要进行变化的论数) 和 k(操作次数)的大小进行一个判断 47 if(min(vis[i], k)&1) printf("%c", 'W'+'B'-s[i]); 48 else printf("%c", s[i]); 49 } 50 }