题意:给定一个字符串,求其中一个由循环子串构成且循环次数最多的一个子串,有多个就输出最小字典序的。
题解:后缀数组+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 }