思维+双指针+环——cf1244F

/*
可以发现一个性质:连续两个相同色块永远不会变色
继而可以发现,这个色段每次迭代都向左向右拓展长度1,直到撞上其他扩张的色段 
所以预处理出所有连续色段,然后对于所有不在色段里的点,我们可以预测其最终的颜色:
    其本身每次迭代改变一次颜色,如果k>= 离其最近的那个色段到其的距离Len,那么其就会被那个色段覆盖
    那么就要预处理出这些点两侧最近的色段距离和颜色 
    
由于是环形,所以扩张两倍即可来求边界 
*/
#include<bits/stdc++.h>
#include<vector>
using namespace std;
#define N 400005
 
int f[N],c[N],k,n,L[N],R[N];
char s[N];
 
int main(){
    cin>>n>>k;
    memset(c,0x3f,sizeof c);
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)
        if(s[i]=='B')c[i]=c[i+n]=0;
        else c[i]=c[i+n]=1;
    c[0]=c[n];c[2*n+1]=c[1];
    
    for(int i=1;i<=2*n;i++)
        if(c[i]==c[i-1] || c[i]==c[i+1])
            f[i]=1;//连续点标记为1 
    
    //特判没有连续段,都是连续段
    int cnt=0;
    for(int i=1;i<=n;i++)cnt+=f[i];
    if(cnt==0){//无连续段 
        if(k%2==0){
            printf("%s",s+1);
        }
        else {
            for(int i=1;i<=n;i++)
                if(s[i]=='B')cout<<'W';
                else cout<<'B';
            puts("");
        }
        return 0;
    }
    else if(cnt==n){
        printf("%s",s+1);
        return 0;
    } 
    
    //处理左边界 
    int p=0;
    while(f[p+1]!=1)++p;//找到第一个连续色段 
    for(int i=p+1;i<=2*n;i++)
        if(!f[i])L[i]=p;
        else  p=i;
    
    //处理右边界
    p=2*n+1;
    while(f[p-1]!=1)--p;
    for(int i=p-1;i>=1;i--)
        if(!f[i])R[i]=p;
        else p=i;
//010011,010011        
    for(int i=1;i<=n;i++){//回到环形上 
            if(!f[i] && L[i]==0)
                L[i]=L[i+n];
            if(!f[i] && R[i]>n)
                R[i]-=n;
        }
    
    for(int i=1;i<=n;i++)
        if(f[i]){
            cout<<s[i];
        }
        else {
            int disl,disr;
            if(L[i]>i)
                disl=n-L[i]+i;
            else 
                disl=i-L[i];
            
            if(R[i]<i)
                disr=R[i]+n-i;
            else    
                disr=R[i]-i;
                
            int dis=min(disl,disr);
            if(dis<=k){
                if(disl<disr){//被左侧覆盖 
                    if(disl<i)
                        cout<<s[i-disl];
                    else cout<<s[i+n-disl]; 
                }
                else {//被右侧覆盖 
                    if(i+disr<=n)
                        cout<<s[i+disr];
                    else cout<<s[i+disr-n];
                }
            }
            else {
                int now=(c[i]+k)%2;
                if(now==0)cout<<"B";
                else cout<<"W";
            } 
        }
    puts("");
}
原文地址:https://www.cnblogs.com/zsben991126/p/11724525.html