Maximum repetition substring POJ

来源:互联网 发布:论文写作的意义 知乎 编辑:程序博客网 时间:2024/06/06 05:41

题意:

给定一个字符串,求这个字符串的一个子串,满足子串是循环节循环次数最多的子串,在循环次数相同的时候输出字典序最小的字符串

思路:

参考国家集训队论文算法合集之《后缀数组——处理字符串的有力工具》
首先我们考虑枚举子串的循环节的长度L,我们只考虑循环至少两次的子串,那么可以知道这个子串至少长度为2L,同时如果我们把原串按照0,L,2L,3L,….,iL,(i+1)L,…来划分,那么这个子串可能会覆盖了iL,(i+1)L,假设这个i是满足条件的最小的i,那么我们现在要做的就是找到这个子串的起点是在哪里,可以知道这个起点应该是在[max(0,(i-1)L+1),iL]这个范围内,我们先求出LCP(suffix[iL],suffix[(i+1)L]),然后就不断往左边匹配str[iL-k],str[(i+1)L-k],每遇到一个可以匹配的k,我们知道它都可能是起点,而我们需要找的是在重复次数相同的情况下,字典序最小的子串,所以这些起点都要考虑进去才不会把字典序最小这个条件给遗漏了,然后我们知道这个起点s可以匹配s+L的后缀LCP(suffix[iL],suffix[(i+1)L])+k个字符,然后这里的重复次数就是这个匹配的字符个数/L+1,然后更新答案即可

代码:

#define debug printf#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<queue>#include<vector>#include<cmath>using namespace std;const int maxn=200000+100;int kase=0;void solve();char str[maxn];struct SuffixArray{    int s[maxn];    int sa[maxn];    int ran[maxn];    int height[maxn];    int t[maxn],t2[maxn],c[maxn];    int n;    void clear()    {        n=0;memset(sa,0,sizeof(sa));    }    void build_sa(int m)    {        int i,*x=t,*y=t2;        for(i=0;i<m;i++)    c[i]=0;        for(i=0;i<n;i++)    c[x[i]=s[i]]++;        for(i=1;i<m;i++)    c[i]+=c[i-1];        for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;        for(int k=1;k<=n;k<<=1){            int p=0;            for(i=n-k;i<n;i++)  y[p++]=i;            for(i=0;i<n;i++)    if(sa[i]>=k)    y[p++]=sa[i]-k;            for(i=0;i<m;i++)    c[i]=0;            for(i=0;i<n;i++)    c[x[y[i]]]++;            for(i=1;i<m;i++)    c[i]+=c[i-1];            for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];            swap(x,y);            p=1;x[sa[0]]=0;            for(i=1;i<n;i++)                x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;                if(p>=n)    break;                m=p;        }    }    void build_height()    {        int i,j,k=0;        for(i=0;i<n;i++){            ran[sa[i]]=i;        }        for(i=0;i<n;i++){            if(k)   k--;            j=sa[ran[i]-1];            while(s[i+k]==s[j+k])   k++;            height[ran[i]]=k;        }    }};SuffixArray sa;void add(int ch){    sa.s[sa.n++]=ch;}void RMQ_init(int * A,int n);int RMQ(int L,int R);int main(){    kase=0;    while(~scanf("%s",str)){        kase++;        if(strcmp(str,"#")==0)  break;        solve();    }    return 0;}void solve(){    sa.clear();    int len=strlen(str);    for(int j=0;j<len;j++){        add(str[j]-'a'+1);    }    add(0);    sa.build_sa(27);    sa.build_height();    RMQ_init(sa.height,sa.n);//  for(int i=0;i<sa.n;i++){//        debug("hh%d %d\n",i,sa.sa[i]);//  }    int ans,lef,righ;    ans=1;    lef=righ=0;    for(int L=1;L<=len;L++){//        debug("%d\n",L);        int K;        int p,q;        for(int i=0;((i+1)*L)<len;i++){            char x=str[i*L],y=str[(i+1)*L];            if(x!=y)    continue;            int ql,qr;            ql=sa.ran[i*L],qr=sa.ran[(i+1)*L];            if(ql>qr)   swap(ql,qr);            ql++;            K=RMQ(ql,qr);//          debug("%d %d %d\n",L,i,K);            p=(i*L),q=((i+1)*L);            int bound=max(0,(i-1)*L+1);                int res=(K/L)+1;//                p++;                if(res>ans||(res==ans&&sa.ran[p]<sa.ran[lef])){                    ans=res;                    lef=p;                    righ=p+res*L;                }            p--;q--;            while(p>=bound&&str[p]==str[q]){                K++;//              debug("%d\n",K);                int res=(K/L)+1;//                p++;                if(res>ans||(res==ans&&sa.ran[p]<sa.ran[lef])){                    ans=res;                    lef=p;                    righ=p+res*L;                }                p--;q--;            }        }    }    printf("Case %d: ",kase);//  righ=ans+lef;    if(ans==1){        char maxv='z';        for(int i=0;i<len;i++){            if(str[i]<maxv){                maxv=str[i];            }        }        printf("%c\n",str[sa.sa[1]]);        return;    }    for(int i=lef;i<righ;i++){        printf("%c",str[i]);    }    printf("\n");}int d[maxn][20];void RMQ_init(int * A,int n){    for(int i=0;i<n;i++){        d[i][0]=A[i];//      debug("%d %d\n",i,A[i]);    }    for(int j=1;(1<<j)<=n;j++){        for(int i=0;i+(1<<j)-1<n;i++){            d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);        }    }}int RMQ(int L,int R){    int k=0;    while((1<<(k+1))<=R-L+1)    k++;    return min(d[L][k],d[R-(1<<k)+1][k]);}/*zzbzbzbaccdbaccdbacbdbacbdxbcabcabedbeaabcabcabcabaccdaccaccddcacacaacadbabbabaabaabaabababaabaabaabaccabababcdaabbccaabcbcbabapedabacewqpzababaaa#*/