poj 3693 后缀数组
链接:点我
1 /* 2 * POJ 3693 Maximum repetition substring 3 * 先穷举长度L,然后求长度为L的子串最多能连续出现多少次 4 * 既然长度为L的串重复出现,那么str[0],str[l],str[2*l]……中肯定有两个连续的出现在字符串中。 5 那么就枚举连续的两个,然后从这两个字符前后匹配,看最多能匹配多远。 6 即以str[i*l],str[i*l+l]前后匹配,这里是通过查询suffix(i*l),suffix(i*l+l)的最长公共前缀 7 通过rank值能找到i*l,与i*l+l的排名,我们要查询的是这段区间的height的最小值,通过RMQ预处理 8 达到查询为0(1)的复杂度, 9 设LCP长度为M, 则答案显然为M / L + 1, 但这不一定是最好的, 因为答案的首尾不一定再我们枚举的位置上. 我的解决方法是, 我们考虑M % L的值的意义, 我们可以认为是后面多了M % L个字符, 但是我们更可以想成前面少了(L - M % L)个字符! 所以我们求后缀j * L - (L - M % L)与后缀(j + 1) * L - (L - M % L)的最长公共前缀。 10 即把之前的区间前缀L-M%L即可。 11 然后把可能取到最大值的长度L保存,由于 题目要求字典序最小,通过sa数组进行枚举,取到的第一组,肯定是字典序最小的。 12 */ 13 14 #include <iostream> 15 #include <stdio.h> 16 #include <algorithm> 17 #include <string.h> 18 using namespace std; 19 const int MAXN=100010; 20 21 /* 22 * 倍增算法求后缀数组 23 */ 24 int sa[MAXN]; 25 int t1[MAXN],t2[MAXN],c[MAXN]; 26 int rank[MAXN],height[MAXN]; 27 void build_sa(int s[],int n,int m) 28 { 29 int i,j,p,*x=t1,*y=t2; 30 for(i=0;i<m;i++)c[i]=0; 31 for(i=0;i<n;i++)c[x[i]=s[i]]++; 32 for(i=1;i<m;i++)c[i]+=c[i-1]; 33 for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i; 34 for(j=1;j<=n;j<<=1) 35 { 36 p=0; 37 for(i=n-j;i<n;i++)y[p++]=i; 38 for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j; 39 for(i=0;i<m;i++)c[i]=0; 40 for(i=0;i<n;i++)c[x[y[i]]]++; 41 for(i=1;i<m;i++)c[i]+=c[i-1]; 42 for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; 43 swap(x,y); 44 p=1;x[sa[0]]=0; 45 for(i=1;i<n;i++) 46 x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++; 47 if(p>=n)break; 48 m=p; 49 } 50 } 51 void getHeight(int s[],int n) 52 { 53 int i,j,k=0; 54 for(i=0;i<=n;i++)rank[sa[i]]=i; 55 for(i=0;i<n;i++) 56 { 57 if(k)k--; 58 j=sa[rank[i]-1]; 59 while(s[i+k]==s[j+k])k++; 60 height[rank[i]]=k; 61 } 62 } 63 int mm[MAXN]; 64 int best[20][MAXN]; 65 void initRMQ(int n) 66 { 67 mm[0]=-1; 68 for(int i=1;i<=n;i++) 69 mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1]; 70 for(int i=1;i<=n;i++)best[0][i]=i; 71 for(int i=1;i<=mm[n];i++) 72 for(int j=1;j+(1<<i)-1<=n;j++) 73 { 74 int a=best[i-1][j]; 75 int b=best[i-1][j+(1<<(i-1))]; 76 if(height[a]<height[b])best[i][j]=a; 77 else best[i][j]=b; 78 } 79 } 80 int askRMQ(int a,int b) 81 { 82 int t; 83 t=mm[b-a+1]; 84 b-=(1<<t)-1; 85 a=best[t][a];b=best[t][b]; 86 return height[a]<height[b]?a:b; 87 } 88 int lcp(int a,int b) 89 { 90 a=rank[a];b=rank[b]; 91 if(a>b)swap(a,b); 92 return height[askRMQ(a+1,b)]; 93 } 94 char str[MAXN]; 95 int r[MAXN]; 96 int a[MAXN]; 97 int main() 98 { 99 //freopen("in.txt","r",stdin); 100 //freopen("out.txt","w",stdout); 101 int iCase=0; 102 while(scanf("%s",str)==1) 103 { 104 if(strcmp(str,"#")==0)break; 105 iCase++; 106 int n=strlen(str); 107 for(int i=0;i<=n;i++)r[i]=str[i]; 108 build_sa(r,n+1,128); 109 getHeight(r,n); 110 initRMQ(n); 111 int cnt=0,mmax=0; 112 for(int l=1;l<n;l++) 113 { 114 for(int i=0;i+l<n;i+=l) 115 { 116 int t1=lcp(i,i+l); 117 int step=t1/l+1; 118 int k=i-(l-t1%l); 119 if(k>=0&&t1%l) 120 { 121 if(lcp(k,k+l)>=t1)step++; 122 } 123 if(step>mmax) 124 { 125 mmax=step; 126 cnt=0; 127 a[cnt++]=l; 128 } 129 else if(step==mmax) 130 a[cnt++]=l; 131 } 132 } 133 int len=-1,st; 134 for(int i=1;i<=n&&len==-1;i++) 135 { 136 for(int j=0;j<cnt;j++) 137 { 138 int l=a[j]; 139 if(lcp(sa[i],sa[i]+l)>=(mmax-1)*l) 140 { 141 len=l; 142 st=sa[i]; 143 break; 144 } 145 } 146 } 147 str[st+len*mmax]=0; 148 printf("Case %d: %s\n",iCase,str+st); 149 } 150 return 0; 151 }