最长重复子串(可重叠) 后缀数组

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 }

 

 

posted @ 2013-02-05 21:11  proverbs  阅读(344)  评论(0编辑  收藏  举报