Live2d Test Env

POJ3693Maximum repetition substring (循环节)(后缀数组+RMQ)

The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R 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

ccabababc
daabbccaa
#

Sample Output

Case 1: ababab
Case 2: aa

题意:

求里面一段字符串,它的循环次数最多,如果有多个,输出最小字典序的一个。

思路就不说了,老题,可以去看论文。但是至少需要知道循环节的性质(具体的去KMP那里去看),大概是这样:

 s1=x y z

 s2=   x y z。如果,s1=s2,且下面的x对应上面的y,下面的y对应上面的z,则x=y ,y=z,则x=y=z。那么他们(x,y,z)就是循环节,而且循环了4次,上面的xyz和下面的z。

下面说一下我的bug。。。

  • 手写的swap居然WA了,写在头文件下面的东西找bug根本找不到啊。。。TT,找到的时候WA的一声就哭出来了。
//应该是因为疑惑运算超过int了
int min(int a,int b)  { if(a<b) return a;return b;}
void swap(int a,int b) {a^=b;b^=a;a^=b;} 

 

  • 逻辑运算少加了括号。
//注意下面的括号,丢了很严重,不要问我怎么知道的 
       for(int i=2;i<=N;i++) Rank[sa[i]]=Rank[sa[i-1]]+(A[sa[i]]==A[sa[i-1]]&&B[sa[i]]==B[sa[i-1]]?0:1);

 

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
using namespace std;
const int maxn=2000010;
char ch[maxn];
int min(int a,int b)  { if(a<b) return a;return b;}
struct SA
{
    int Rank[maxn],sa[maxn],tsa[maxn],A[maxn],B[maxn],cntA[maxn],cntB[maxn],N;
    int ht[maxn],Min[maxn][30];
    int sort()
    {
        N=strlen(ch+1);
        for(int i=0;i<=256;i++) cntA[i]=0;
        for(int i=1;i<=N;i++) cntA[ch[i]-'a'+1]++;
        for(int i=1;i<=256;i++) cntA[i]+=cntA[i-1];
        for(int i=N;i>=1;i--) sa[cntA[ch[i]-'a'+1]--]=i;
        Rank[sa[1]]=1;
        for(int i=2;i<=N;i++)  Rank[sa[i]]=Rank[sa[i-1]]+(ch[sa[i]]==ch[sa[i-1]]?0:1);//这个括号不要少。 
        for(int l=1;Rank[sa[N]]<N;l<<=1){
            for(int i=0;i<=N;i++) cntA[i]=cntB[i]=0;
            for(int i=1;i<=N;i++) cntA[A[i]=Rank[i]]++;
            for(int i=1;i<=N;i++) cntB[B[i]=i+l<=N?Rank[i+l]:0]++;
            for(int i=1;i<=N;i++) cntA[i]+=cntA[i-1],cntB[i]+=cntB[i-1];
            for(int i=N;i>=1;i--) tsa[cntB[B[i]]--]=i;
            for(int i=N;i>=1;i--) sa[cntA[A[tsa[i]]]--]=tsa[i];
            Rank[sa[1]]=1;//注意下面的括号,丢了很严重,不要问我怎么知道的 
            for(int i=2;i<=N;i++) Rank[sa[i]]=Rank[sa[i-1]]+(A[sa[i]]==A[sa[i-1]]&&B[sa[i]]==B[sa[i-1]]?0:1);
        }
    }
    int height(){
        for(int i=1,j=0;i<=N;i++){
            if(j) j--;
            while(ch[i+j]==ch[sa[Rank[i]-1]+j]) j++;
            ht[Rank[i]]=j;
        }
    }
    int get_rmq()
    {
        for(int i=1;i<=N;i++)  Min[i][0]=ht[i];
        for(int j=1;(1<<j)<=N;j++){
            for(int i=1;i+(1<<j)-1<=N;i++) 
             Min[i][j]=min(Min[i][j-1],Min[i+(1<<(j-1))][j-1]);
        }
    }
    int query_rmq(int L,int R)
    {
        if(L>R) swap(L,R); L++;
        int k=log2(R-L+1);
        return min(Min[L][k],Min[R-(1<<k)+1][k]);
    }
    void solve()//solve这一段是抄的,说实话我觉得有点乱。。。 
    {
        int ans=0,al=0,ar=0;
        for(int L=1;L*2<=N;L++){        
            for(int i=0;L*(i+1)+1<=N;i++){
                int x=L*i+1,y=L*(i+1)+1;
                if(ch[x]!=ch[y]) continue;    
                int z=query_rmq(Rank[x],Rank[y]);
                int t1=y+z-1,t0=0;
                for(int j=0;j<=L-1;j++){ 
                    if(x-j<1 || ch[x-j]!=ch[y-j]) break;
                    t0=x-j;int now=((t1-t0+1)/L);
                    if(now>ans || (now==ans && Rank[t0]<Rank[al])){
                        ans=now;al=t0;ar=t0+now*L-1;
                    }
                }
            }
        }
        if(ans==0)  printf("%c\n",ch[sa[1]]);
        else {
            for(int i=al;i<=ar;i++)  printf("%c",ch[i]);printf("\n");
        }
    }
}Sa;
int main()
{
    int Case=0;
    while(~scanf("%s",ch+1)){
        if(ch[1]=='#') return 0; 
        printf("Case %d: ",++Case); 
        Sa.sort();
        Sa.height();;
        Sa.get_rmq();
        Sa.solve();
    }  return 0; 
}

 

posted @ 2017-12-29 22:41  nimphy  阅读(281)  评论(0编辑  收藏  举报