SPOJ:REPEATS

http://www.spoj.com/problems/REPEATS/

  求重复次数最多的连续重复子串。

  论文题。枚举子串长度L,重复一次是肯定的,我们考虑至少重复两次的情况。那么在1,L+1,2L+1...kL+1这些位置一定会覆盖至少连续的两个。于是我们枚举连续的两个位置,向前向后匹配,匹配总长/L+1即为重复次数。

#include<bits/stdc++.h>
using namespace std;
const int maxn=50015;
int n,len;char s[maxn<<1];
struct Tsuffix_array{
    static const int maxn=::maxn<<1;
    int sum[maxn],sa[maxn],rank[maxn],tsa[maxn],trank[maxn];
    bool cmp(int i,int j,int l){
        if (i+l>len||j+l>len) return 0;
        return rank[i]==rank[j]&&rank[i+l]==rank[j+l];
    }
    void suffix_sort(){
        int m=255,p,i,j;
        for (i=0;i<=m;++i) sum[i]=0;
        for (i=1;i<=len;++i) ++sum[rank[i]=s[i]];
        for (i=1;i<=m;++i) sum[i]+=sum[i-1];
        for (i=len;i>=1;--i) sa[sum[rank[i]]--]=i;
        for (p=0,j=1;p<len;j<<=1,m=p){
            for (p=0,i=len-j+1;i<=len;++i) tsa[++p]=i;
            for (i=1;i<=len;++i) if (sa[i]>j) tsa[++p]=sa[i]-j;
            for (i=0;i<=m;++i) sum[i]=0;
            for (i=1;i<=len;++i) ++sum[rank[tsa[i]]];
            for (i=1;i<=m;++i) sum[i]+=sum[i-1];
            for (i=len;i>=1;--i) sa[sum[rank[tsa[i]]]--]=tsa[i];
            for (p=trank[sa[1]]=1,i=2;i<=len;++i) trank[sa[i]]=cmp(sa[i],sa[i-1],j)?p:++p;
            memcpy(rank,trank,sizeof(int)*(len+1));
        }
    }
    static const int maxk=20;
    int height[maxn],fmn[maxk][maxn];
    void get_height(){
        for (int h=0,i=1;i<=len;++i){
            if (rank[i]==1) continue;
            for (h?--h:0;s[i+h]==s[sa[rank[i]-1]+h];++h);
            height[rank[i]]=h;
        }
        for (int i=2;i<=len;++i) fmn[0][i]=height[i];
        for (int k=1;k<maxk;++k)
            for (int i=1<<k;i<=len;++i)
                fmn[k][i]=min(fmn[k-1][i],fmn[k-1][i-(1<<(k-1))]);
    }
    int LCP(int x,int y){
        if (x>y) swap(x,y);
        int k=log2(y-(++x)+1);
        return min(fmn[k][y],fmn[k][x+(1<<k)-1]);
    }
    int check(int l){
        int res=0;
        for (int i=1,j=l+1;j<=n;i=j,j=i+l){
            int Rmatch=LCP(rank[i],rank[j]);
            int Lmatch=LCP(rank[n+1+(n-i+1)],rank[n+1+(n-j+1)]);
            res=max(res,(Lmatch+Rmatch-1)/l+1);
        }
        return res;
    }
}SA;
void init(){
    scanf("%d",&n);s[n+1]=1;len=(n<<1)+1;s[len+1]=0;
    for (int i=1;i<=n;++i){char c[2];scanf("%s",c);s[i]=c[0];}
    for (int i=1;i<=n;++i) s[n+1+(n-i+1)]=s[i];
}
void work(){
    SA.suffix_sort();
    SA.get_height();
    int res=1;
    for (int i=1;i<=n/2;++i) res=max(res,SA.check(i));
    printf("%d
",res);
}
int main(){
    int cases;scanf("%d",&cases);
    while (cases--){init();work();}
    return 0;
}
my code
原文地址:https://www.cnblogs.com/iamCYY/p/4738363.html