POJ 3693 Maximum repetition substring RMQ+后缀数组

来源:互联网 发布:php is_string 编辑:程序博客网 时间:2024/05/18 00:38

The repetition number of a string is defined as the maximum number R such that the string can be partitioned intoR same consecutive substrings. For example, the repetition number of "ababab" is 3 and "ababa" is 1.

Given a string containing lowercase letters, you are to find a substring of it with maximum repetition number.

Input

The input consists of multiple test cases. Each test case contains exactly one line, which
gives a non-empty string consisting of lowercase letters. The length of the string will not be greater than 100,000.

The last test case is followed by a line containing a '#'.

Output

For each test case, print a line containing the test case number( beginning with 1) followed by the substring of maximum repetition number. If there are multiple substrings of maximum repetition number, print the lexicographically smallest one.

Sample Input
ccabababcdaabbccaa#
Sample Output
Case 1: ababab

Case 2: aa

题意:给你一个串,让你求出重复次数最多的连续重复子串,若有多个则输出字典序最小的那个

思路:

官方题解

我自己的理解:

首先枚举重复串的长度l,如果重复度大于1原串中st[0],st[l],st[2*l]...中一定存在两个连续相等的情况,假如st[i*l]=st[(i+1)*l],则再分两步走

1.首先先求出两者对应后缀串的最大前缀,这样就能确定末尾

2,然后从这两个元素向前匹配,知道不能再匹配为止,这样就能确定开头

注意在判断的时候如果枚举的l对应好几种情况则选择rank最小的

3.在确定两个后缀的最大前缀时,需要用到求在一段区间内height数组的最小值,这时需要用到RMQ算法 预处理一下在直接查找即可

ac代码:

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>using namespace std;const int N=2*100100;int cl,rk[N],sa[N],Rs[N],y[N],wr[N],h[N],r[N][30];char c[N];int minn(int x,int y){return x<y ? x:y;}void get_sa(int m){    for(int i=1;i<=cl;i++) rk[i]=c[i]-'a'+1;    for(int i=1;i<=m;i++) Rs[i]=0;    for(int i=1;i<=cl;i++) Rs[rk[i]]++;    for(int i=1;i<=m;i++) Rs[i]+=Rs[i-1];    for(int i=cl;i>=1;i--) sa[Rs[rk[i]]--]=i;        int ln=1,p=0;    while(p<cl)    {        int k=0;        for(int i=cl-ln+1;i<=cl;i++) y[++k]=i;        for(int i=1;i<=cl;i++) if(sa[i]>ln) y[++k]=sa[i]-ln;                for(int i=1;i<=cl;i++) wr[i]=rk[y[i]];        for(int i=1;i<=m;i++) Rs[i]=0;        for(int i=1;i<=cl;i++) Rs[wr[i]]++;        for(int i=1;i<=m;i++) Rs[i]+=Rs[i-1];        for(int i=cl;i>=1;i--) sa[Rs[wr[i]]--]=y[i];                for(int i=1;i<=cl;i++) wr[i]=rk[i];        for(int i=cl+1;i<=cl+ln;i++) wr[i]=0;        p=1;rk[sa[1]]=1;        for(int i=2;i<=cl;i++)        {            if(wr[sa[i]]!=wr[sa[i-1]] || wr[sa[i]+ln]!=wr[sa[i-1]+ln]) p++;            rk[sa[i]]=p;        }        ln*=2,m=p;    }    sa[0]=0,rk[0]=0;}void get_h(){    int k=0,j;    for(int i=1;i<=cl;i++) if(rk[i]!=1)    {        j=sa[rk[i]-1];        if(k) k--;        while(c[j+k]==c[i+k] && j+k<=cl && i+k<=cl) k++;        h[rk[i]]=k;    }    h[1]=0;}void get_rmq(){    for(int i=1;i<=cl;i++) r[i][0]=h[i];    for(int j=1;(1<<j)<=cl;j++)        for(int i=1;i+(1<<j)-1<=cl;i++)        {            r[i][j]=minn(r[i][j-1],r[i+(1<<(j-1))][j-1]);        }}int query_rmq(int i,int j){    if(i>j) swap(i,j);    i++;    int k=0;    while(i+(1<<(k+1)) <= j) k++;    return minn(r[i][k],r[j-(1<<k)+1][k]);}int main(){    int x,y,z,t0,t1,now,ans,al,ar,T=0;    while(1)    {        scanf("%s",c+1);        cl=strlen(c+1);        if(cl==1 && c[1]=='#') return 0;        printf("Case %d: ",++T);        get_sa(30);        get_h();        get_rmq();        ans=0;al=ar=0;        for(int L=1;L*2<=cl;L++)        {            for(int i=0;L*(i+1)+1<=cl;i++)            {                x=L*i+1,y=L*(i+1)+1;                if(c[x]!=c[y]) continue;                    z=query_rmq(rk[x],rk[y]);                t1=y+z-1;                t0=0;                for(int j=0;j<=L-1;j++)//往前匹配                {                    if(x-j<1 || c[x-j]!=c[y-j]) break;                    t0=x-j;                    now=((t1-t0+1)/L);                    if(now>ans || (now==ans && rk[t0]<rk[al])) ans=now,al=t0,ar=t0+now*L-1;                }            }        }        if(ans==0) printf("%c\n",c[sa[1]]);        else         {            for(int i=al;i<=ar;i++) printf("%c",c[i]);printf("\n");        }    }        return 0;}

0 0
原创粉丝点击