zoukankan      html  css  js  c++  java
  • [APIO2014] [Uoj103] [Bzoj3676] Palindromes回文串 [Manacher,后缀数组]

    用Manacher算法枚举回文子串,每次在后缀数组排序后的后缀数组中二分,因为用某一后缀和其他子串分别求匹配的长度,匹配长度在排序后该后缀的两侧具有单调性(匹配长度为min{H[x]|i<=x<=j},所以对于查询min(H[x])用ST表O(n)预处理,O(1)查询即可。Manacher时间复杂度O(n),后缀数组复杂度O(nlogn),总复杂度O(nlogn)。注意二分时的边界条件!

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <ctime>
    #include <algorithm>
    
    using namespace std;
    
    long long    Ans;
    int    A[310000],B[310000],U[310000];
    int    SA[310000],*Rank,H[310000],Tmp[310000];
    int    lg2[310000],ST[310000][20],p[610000];
    char    str[610000];
    
    void    Get_H(const int n)
    {
        int    i,j,k=0;
        for(i=0;i<n;H[Rank[i++]]=k)
            for(k?k--:k,j=SA[Rank[i]-1];str[i+k]==str[j+k];++k);
        for(i=2;i<=n;++i)lg2[i]=lg2[i>>1]+1;
        for(i=1;i<=n;++i)ST[i][0]=H[i];
        for(j=1;(1<<j)<=n;++j)
        {
            for(i=1;i+(1<<j)-1<=n;++i)
            {
                ST[i][j]=min(ST[i][j-1],ST[i+(1<<(j-1))][j-1]);
            }
        }
        return ;
    }
    
    int    Query(const int l,const int r)
    {
        int    temp=lg2[r-l+1];
        return min(ST[l][temp],ST[r-(1<<temp)+1][temp]);
    }
    
    bool    cmp(const int * s,const int a,const int b,const int l)
    {
        return s[a]==s[b] && s[a+l]==s[b+l];
    }
    
    int*    Get_SA(const int n,int    m)
    {
        int    i,j,_p,*x=A,*y=B;
        for(i=0;i<m;++i)U[i]=0;
        for(i=0;i<n;++i)U[x[i]=str[i]]++;
        for(i=1;i<m;++i)U[i]+=U[i-1];
        for(i=n-1;i>=0;--i)SA[--U[x[i]]]=i;
    
        for(j=1,_p=1;_p<n;m=_p,j<<=1)
        {
            for(_p=0,i=n-j;i<n;++i)y[_p++]=i;
            for(i=0;i<n;++i)if(SA[i]>=j)y[_p++]=SA[i]-j;
            for(i=0;i<n;++i)Tmp[i]=x[y[i]];
            for(i=0;i<m;++i)U[i]=0;
            for(i=0;i<n;++i)U[Tmp[i]]++;
            for(i=1;i<m;++i)U[i]+=U[i-1];
            for(i=n-1;i>=0;--i)SA[--U[Tmp[i]]]=y[i];
            for(swap(x,y),_p=1,x[SA[0]]=0,i=1;i<n;++i)
                x[SA[i]]=cmp(y,SA[i-1],SA[i],j)?_p-1:_p++;
        }
        return x;
    }
    
    long long    Calc(int l,int r,const int n)
    {
        l=(l-1)>>1,r=(r-2)>>1;
        int    pos=Rank[l],L,R,temp=1;
    
        L=0,R=pos;
    
        while(L<R-1)
        {
            int    mid=L+((R-L)>>1);
            if(Query(mid+1,pos)>=r-l+1)R=mid;
            else    L=mid;
        }
    
        temp+=pos-R;
        L=pos,R=n+1;
    
        while(L<R-1)
        {
            int    mid=L+((R-L)>>1);
            if(Query(pos+1,mid)>=r-l+1)L=mid;
            else    R=mid;
        }
        temp+=L-pos;
        return (long long)temp*(r-l+1);
    }
    
    
    
    
    void    Manacher(const int n)
    {
        int    i,pos=0;
        for(i=n-1;i>=0;--i)
        {
            str[i+i+2]=str[i];
            str[i+i+1]='#';
        }
        str[0]='^';str[n<<1|1]='#';str[(n+1)<<1]='$';
        for(i=1;i<=(n<<1|1);++i)
        {
            if(p[pos]+pos>i)
                p[i]=min(p[(pos<<1)-i],p[pos]+pos-i);
            else    p[i]=1;
            while(str[i-p[i]]==str[i+p[i]])
            { if(i+p[i]>p[pos]+pos) Ans=max(Ans,Calc(i-p[i],i+p[i],n)); p[i]++; }
            if(pos+p[pos]<i+p[i])pos=i;
        }
        
        return ;
    }
    
    
    int main()
    {
        int    n;
    
        scanf("%s",str);
    
        n=strlen(str);
        Rank=Get_SA(n+1,256);
        Get_H(n);
        Manacher(n);
    
        printf("%lld",Ans);
    
        return 0;
    }
  • 相关阅读:
    android模拟器中文乱码
    Broadcast Receviewer
    Spring XML配置里的Bean自动装配
    Spring中的Bean配置
    Spring第一个helloWorld
    MyBatis向数据库中批量插入数据
    MyBatis联合查询和使用association 进行分步式查询
    MyBatis编写映射文件实现增删改操作 附说明及代码
    MyBatis全局配置文件MyBatis-config.xml代码
    MyBatis全局配置文件mybatis-config.xml
  • 原文地址:https://www.cnblogs.com/Gster/p/4981889.html
Copyright © 2011-2022 走看看