• 思维+双指针+环——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("");
    }
  • 相关阅读:
    聊一聊正则表达式,最全最常用总结
    11个优秀的Android开发开源项目
    一招教你打造一个滑动置顶的视觉特效
    这些优质的电子书 开发必备【干货精选】
    用Kotlin破解Android版微信小游戏跳一跳
    2017上半年技术文章集合【Android】—184篇文章分类汇总
    经常用到的字符串函数
    EhLib使用说明
    Delphi中本年、本月、本周的第一天和最后天
    Delphi中关于listview的一些使用
  • 原文地址:https://www.cnblogs.com/zsben991126/p/11724525.html
Copyright © 2020-2023  润新知