• BZOJ 2342 [Shoi2011]双倍回文(manacher+并查集)


    【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2342

    【题目大意】

      记Wr为W串的倒置,求最长的形如WWrWWr的串的长度。

    【题解】

      我们发现要找到这样一个双倍回文,我们可以采取在大的回文串中寻找小的回文串的方式,
      在回文串i中找到回文串j满足j+r[j]>=i那么(i-j)<<1就可以用来更新答案。
      在查找过程中,我们发现在下标小的i中无法被用到的j在下标大的i中也无法被用到,
      因此对于无效的查找区间我们用并查集进行优化

    【代码】

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N=500010;
    int n,f[N<<1],r[N<<1],ans;
    char s[N],c[N<<1];
    void manacher(){
        for(int i=1;i<=n;i++)c[i<<1]=s[i],c[(i<<1)+1]='#';
        c[1]='#';c[n<<1|1]='#';c[0]='&';c[(n+1)<<1]='$';
        int j=0,k; n=n<<1|1;
        for(int i=1;i<=n;){
            while(c[i-j-1]==c[i+j+1])j++;
            r[i]=j;
            for(k=1;k<=j&&r[i]-k!=r[i-k];k++)r[i+k]=min(r[i-k],r[i]-k);
            i+=k;j=max(j-k,0);
        }
    }
    int sf(int x){return f[x]==x?x:f[x]=sf(f[x]);}
    int main(){
        while(~scanf("%d",&n)){
            scanf("%s",s+1); 
    		manacher(); ans=0;
            for(int i=1;i<=n;i++)f[i]=(c[i]=='#')?i:(i+1);
            for(int i=3;i<n;i+=2){
                int j=sf(max(i-(r[i]>>1),1));
                for(;j<i&&j+r[j]<i;f[j]=sf(j+1),j=f[j]);
                if(j<i)if((i-j)<<1>ans)ans=(i-j)<<1;
            }printf("%d
    ",ans);
        }return 0;
    }
  • 相关阅读:
    JavaScript总结(一)
    序列化函数
    random与os,sys模块
    认识模块
    时间模块
    日志处理
    异常处理
    类的约束
    反射
    区分函数以及方法
  • 原文地址:https://www.cnblogs.com/forever97/p/bzoj2342.html
Copyright © 2020-2023  润新知