zoukankan      html  css  js  c++  java
  • URAL 1297:后缀数组求最长回文串

    求最长回文串

    策略是枚举中心位置往两边拓展,这里要分长度为奇数、偶数的情况

    n^2的复杂度无法接受,枚举中心后,这里用后缀数组来快速求回文长度

    首先在字符串末尾插入一个未出现过的字符,目的是避免字符串翻转后拼接到末尾时的首部和原字符串末尾连接成新的后缀

    比如说abac->abaccaba,这里的acca后缀是不存在的,所以应该变成abac#caba,阻隔开来

    然后就是枚举中间点

    首先说长度为奇数的情况

    因为回文串至少长度为1,我们从下标1开始枚举至n-1

    例如 0 1 2 3 4 5 6 7 8

       a b a c # c a b a  

      枚举到1时,我用2号位置起始的后缀和8号位置的后缀求最长公共前缀。因为8号位置的字符相当于是原串中的0号位置,相当于中心对称。以此类推

    再来说偶数的情况

    从0开始枚举至n-1。看看下面的例子理解一下为何从0开始

    例如 0 1 2 3 4 5 6 7 8 9 10

       a b b a c # c a b b a  

      枚举到1时,我用2号位置的后缀和9号位置的后缀求最长公共前缀,9、10号对应原串1、0号,相当于轴对称。以此类推

    不断维护长度最大值和起始位置,最后输出就行了

    #include"cstdio"
    #include"queue"
    #include"cmath"
    #include"stack"
    #include"iostream"
    #include"algorithm"
    #include"cstring"
    #include"queue"
    #include"map"
    #include"set"
    #include"vector"
    #define ll long long
    #define mems(a,b) memset(a,b,sizeof(a))
    #define ls pos<<1
    #define rs pos<<1|1
    
    using namespace std;
    const int MAXE = 500050;
    const int MAXN = 2010;
    const int INF = 0x3f3f3f3f;
    
    int sa[MAXN];
    int X[MAXN],Y[MAXN],radix[MAXN],trank[MAXN];
    int RANK[MAXN];
    char arr[MAXN];
    
    void get_sa(char *r,int n,int m){
        int i,j,p,*Rank=X,*tsa=Y,*t;
        for (i=0;i<m;i++)  radix[i]=0;
        for (i=0;i<n;i++) radix[Rank[i]=r[i]]++;
        for (i=1;i<m;i++)  radix[i]+=radix[i-1];
        for (i=n-1;i>=0;i--)  sa[--radix[Rank[i]]]=i;
        for (j=1,p=1;p<n;j*=2,m=p)
        {
            for (p=0,i=n-j;i<n;i++) tsa[p++]=i;
            for (i=0;i<n;i++) if (sa[i]>=j) tsa[p++]=sa[i]-j;
            for (i=0;i<n;i++) trank[i]=Rank[tsa[i]];
            for (i=0;i<m;i++) radix[i]=0;
            for (i=0;i<n;i++) radix[trank[i]]++;
            for (i=1;i<m;i++) radix[i]+=radix[i-1];
            for (i=n-1;i>=0;i--) sa[--radix[trank[i]]]=tsa[i];
            for (t=Rank,Rank=tsa,tsa=t,p=1,Rank[sa[0]]=0,i=1;i<n;i++){
                if(tsa[sa[i-1]]==tsa[sa[i]]&&tsa[sa[i-1]+j]==tsa[sa[i]+j]) Rank[sa[i]]=p-1;
                else Rank[sa[i]]=p++;
            }
        }
        for(i = 0; i < n; i ++) RANK[sa[i]] = i;
        //for(i=0;i<n;i++) cout<<height[i]<<' ';cout<<endl;
        /*for(int i=0;i<n;i++){
            for(int j=sa[i];j<n;j++) cout<<r[j];
            cout<<endl;
        }*/
    
    }
    int height[MAXN];
    void get_height(char *r,int n){
        int i,j=0,k=0;
        for(i = 0; i < n; height[RANK[i ++]] = k)
        for(k ? k -- : 0, j = sa[RANK[i]-1]; r[i+k] == r[j+k]; k ++);
    }
    
    int dp[MAXN][20];
    
    void makermq(int n){
        mems(dp,INF);
        for(int i=1;i<=n;i++) dp[i][0]=height[i];
        for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<n;i++) dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
    }
    
    int query(int l,int r){
        if(l>r) swap(l,r);
        l++;
        int k=(int)(log((r-l+1)*1.0)/log(2.0));
        return min(dp[l][k],dp[r-(1<<k)+1][k]);
    }
    
    int main(){
        //freopen("in.txt","r",stdin);
        while(~scanf("%s",arr)){
            int n=strlen(arr);
            int len=n;
            arr[len]='#';
            for(int i=n-1;i>=0;i--) arr[++len]=arr[i];
            arr[++len]='0';
            get_sa(arr,len+1,300);
            get_height(arr,len);
            makermq(len+1);
            int ans=1,p=0;
            for(int i=1;i<n-1;i++){
                int t=query(RANK[i+1],RANK[2*n-i+1]);
                if(2*t+1>ans){
                    ans=t*2+1;
                    p=i-t;
                }
            }
            for(int i=0;i<n-1;i++){
                int t=query(RANK[i+1],RANK[2*n-i]);
                if(2*t>ans){
                    ans=t*2;
                    p=i-t+1;
                }
            }
            for(int i=0;i<ans;i++) cout<<arr[i+p];
            cout<<endl;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    hiho_1081_最短路径1
    hiho_1079_离散化
    hiho_1078_线段树区间修改
    hiho_1069_最近公共祖先3
    【.netcore学习】.netcore添加到 supervisor 守护进程自启动报错
    【.NetCore学习】ubuntu16.04 搭建.net core mvc api 运行环境
    【.NetCore学习】ASP.NET Core EF Core2.0 DB First现有数据库自动生成实体Context
    【vue基础学习】vue.js开发环境搭建
    【vue学习】vue中怎么引用laydate.js日期插件
    【年终总结】个人的2017年年终总结
  • 原文地址:https://www.cnblogs.com/luxiaoming/p/5236994.html
Copyright © 2011-2022 走看看