CF1244F Chips 的题解

题目的字面意思:

就是说给出了一个环,然后对于每一个位置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 }
原文地址:https://www.cnblogs.com/loenvom/p/11872665.html