最长重复子串(可重叠) 后缀数组
http://www.bianchengla.com/course/ds/practise/problem?id=1387
找了半天终于找到一个可以提交的地方。。。
题解:
任何一个重复子串,都必然是某两个后缀的最长公共前缀。
因为,两个后缀的公共前缀,它出现在这两个后缀中,并且起始位置时不同的,所以这个公共前缀必然重复出现两次以上(可重叠)。
而任何两个后缀的最长公共前缀为某一段height值中的最小值,所以最大为height值中的最大值(即某个lcp(sa[i],sa[i+1]))。
所以只要算出height数组,然后输出最大值就可以了。
View Code
1 #include <iostream> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cstdio> 5 #include <algorithm> 6 7 #define N 50050 8 9 using namespace std; 10 11 int wa[N],wb[N],wc[N],wv[N]; 12 int r[N],sa[N]; 13 char str[N]; 14 int rank[N],height[N]; 15 16 inline bool cmp(int *r,int a,int b,int l) 17 { 18 return r[a]==r[b]&&r[a+l]==r[b+l]; 19 } 20 21 inline void da(int *r,int *sa,int n,int m) 22 { 23 int i,j,p,*x=wa,*y=wb,*t; 24 for(i=0;i<m;i++) wc[i]=0; 25 for(i=0;i<n;i++) wc[x[i]=r[i]]++; 26 for(i=1;i<m;i++) wc[i]+=wc[i-1]; 27 for(i=n-1;i>=0;i--) sa[--wc[x[i]]]=i; 28 for(j=1,p=1;p<n;j<<=1,m=p) 29 { 30 for(i=n-j,p=0;i<n;i++) y[p++]=i; 31 for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; 32 for(i=0;i<n;i++) wv[i]=x[y[i]]; 33 for(i=0;i<m;i++) wc[i]=0; 34 for(i=0;i<n;i++) wc[wv[i]]++; 35 for(i=1;i<m;i++) wc[i]+=wc[i-1]; 36 for(i=n-1;i>=0;i--) sa[--wc[wv[i]]]=y[i]; 37 for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++) 38 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 39 } 40 } 41 42 inline void getheight(int *r,int *sa,int n) 43 { 44 int i,j,k=0; 45 for(i=1;i<=n;i++) rank[sa[i]]=i; 46 for(i=0;i<n;height[rank[i++]]=k) 47 for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++); 48 } 49 50 inline void go() 51 { 52 scanf("%s",str); 53 int n=strlen(str); 54 for(int i=0;i<n;i++) r[i]=str[i]; 55 r[n]=0; 56 da(r,sa,n+1,256); 57 getheight(r,sa,n); 58 59 int ans=-1,pos; 60 for(int i=1;i<=n;i++) 61 if(height[i]>ans) ans=height[i],pos=sa[i]; 62 for(int i=pos;i<pos+ans;i++) printf("%c",str[i]); 63 puts(""); 64 } 65 66 int main() 67 { 68 int cas;scanf("%d",&cas); 69 while(cas--) go(); 70 return 0; 71 }
没有人能阻止我前进的步伐,除了我自己!