题意:给定一个字符串,求其中一个由循环子串构成且循环次数最多的一个子串,有多个就输出最小字典序的。

题解:后缀数组+RMQ。

   1、枚举循环串的长度ll,然后如果它出现了两次,那么它一定会覆盖s[0],s[ll],s[ll*2].....这些点中相邻的两个。

   2、再枚举它覆盖的最左边的那个s[ll*i],通过rmq求s[ll*i]与s[ll*i+ll]的最长公共前缀K,可以看出,从[ll*i,ll*i+ll+K]这个区间内,s[ll*i,ll*(i+1)-1]重复出现了K/ll+1次。

   3、在第2步中,还有可能就是循环串并不是从ll*i开始的,所以要枚举它前面[ll*(i-1)+1,ll*i-1]位置的情况。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cmath>
  5 using namespace std;
  6 const int N=100005;
  7 char s[N];
  8 int n,sa[N],height[N],rank[N],tmp[N],top[N];
  9 void makesa()
 10 {
 11     int i,j,len,na;
 12     na=max(256,n);
 13     memset(top,0,sizeof(top));
 14     for(i=0;i<n;i++)top[rank[i]=(s[i]&0xff)]++;
 15     for(i=1;i<na;i++)top[i]+=top[i-1];
 16     for(int i=0;i<n;i++)sa[--top[rank[i]]]=i;
 17     for(len=1;len<n;len<<=1)
 18     {
 19         for(i=0;i<n;i++)
 20         {
 21             j=sa[i]-len;
 22             if(j<0)j+=n;
 23             tmp[top[rank[j]]++]=j;
 24         }
 25         sa[tmp[top[0]=0]]=j=0;
 26         for(i=1;i<n;i++)
 27         {
 28             if(rank[tmp[i]]!=rank[tmp[i-1]]||rank[tmp[i]+len]!=rank[tmp[i-1]+len])
 29                 top[++j]=i;
 30             sa[tmp[i]]=j;
 31         }
 32         memcpy(rank,sa,sizeof(int)*n);
 33         memcpy(sa,tmp,sizeof(int)*n);
 34         if(j>=n-1)
 35             break;
 36     }
 37 }
 38 void lcp()
 39 {
 40     int i,j,k;
 41     for(j=rank[height[i=k=0]=0];i<n-1;i++,k++)
 42     {
 43         while(k>=0&&s[i]!=s[sa[j-1]+k])
 44             height[j]=k--,j=rank[sa[j]+1];
 45     }
 46 }
 47 int st[40][N];
 48 void initrmq()
 49 {
 50     int i,j,k,sk;
 51     for(i=0;i<n;i++)st[0][i]=height[i];
 52     for(i=1,k=2;k<n;i++,k<<=1)
 53     {
 54         for(j=0,sk=(k>>1);j<n;j++,sk++)
 55         {
 56             st[i][j]=st[i-1][j];
 57             if(sk<n&&st[i][j]>st[i-1][sk])
 58             {
 59                 st[i][j]=st[i-1][sk];
 60             }
 61         }
 62     }
 63 }
 64 int lg[N];
 65 int query(int x,int y)
 66 {
 67     if(x>y)
 68         swap(x,y);
 69     x++;
 70     int b=lg[y-x+1];
 71     return min(st[b][x],st[b][y-(1<<b)+1]);
 72 }
 73 struct data
 74 {
 75     int len,r,pos;
 76     data(){}
 77     data(int _len,int _r,int _pos){len=_len;r=_r;pos=_pos;}
 78     bool operator<(const data &ne)const
 79     {
 80         if(r!=ne.r)
 81             return r<ne.r;
 82         return rank[pos]>rank[ne.pos];
 83     }
 84 };
 85 int main()
 86 {
 87     int ca=0;
 88     lg[0]=-1;
 89     for(int i=1;i<N;i++){
 90         lg[i]=(i&(i-1))?lg[i-1]:(lg[i-1]+1);
 91     }
 92     while(gets(s),strcmp(s,"#")!=0)
 93     {
 94         n=strlen(s)+1;
 95         makesa();lcp();initrmq();
 96         int a,b;
 97         data ans(1,1,0);
 98         for(int ll=1;ll<n;ll++)
 99         {
100             for(int i=0;i+ll<n;i+=ll)
101             {
102                 int t,r,k=query(rank[i],rank[i+ll]);
103                 r=k/ll+1;
104                 t=i-ll+k%ll;
105                 if(t>=0&&k%ll!=0&&query(rank[t],rank[t+ll])>=k)
106                 {
107                     r++;
108                     while(t>=0&&t>i-ll&&query(rank[t],rank[t+ll])>=k)
109                     {
110                         data tp(ll,r,t);
111                         if(ans<tp)
112                             ans=tp;
113                         t--;
114                     }
115                 }
116                 else
117                 {
118                     data tp(ll,r,i);
119                     if(ans<tp)
120                         ans=tp;
121                 }
122             }
123         }
124         s[ans.pos+ans.len*ans.r]='\0';
125         printf("Case %d: %s\n",++ca,s+ans.pos);
126     }
127     return 0;
128 }