POJ2774 Long Long Message(后缀数组)

求两个字符串的最长公共子串。

拼接两个字符串中间用特殊字符隔开,max(height[i])(2<=i<=len,suffix(sa[i])与suffix(sa[i-1])分别属于两个字符串的后缀)就是答案!

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<algorithm>
 5 using namespace std;
 6 #define MAXN 222222 
 7 int wa[MAXN],wb[MAXN],wv[MAXN],ws[MAXN];
 8 int cmp(int *r,int a,int b,int l){
 9     return r[a]==r[b] && r[a+l]==r[b+l];
10 }
11 int sa[MAXN],rank[MAXN],height[MAXN];
12 void SA(int *r,int n,int m){
13     int *x=wa,*y=wb;
14 
15     for(int i=0; i<m; ++i) ws[i]=0;
16     for(int i=0; i<n; ++i) ++ws[x[i]=r[i]];
17     for(int i=1; i<m; ++i) ws[i]+=ws[i-1];
18     for(int i=n-1; i>=0; --i) sa[--ws[x[i]]]=i;
19 
20     int p=1;
21     for(int j=1; p<n; j<<=1,m=p){
22         p=0;
23         for(int i=n-j; i<n; ++i) y[p++]=i;
24         for(int i=0; i<n; ++i) if(sa[i]>=j) y[p++]=sa[i]-j;
25         for(int i=0; i<n; ++i) wv[i]=x[y[i]];
26         for(int i=0; i<m; ++i) ws[i]=0;
27         for(int i=0; i<n; ++i) ++ws[wv[i]];
28         for(int i=1; i<m; ++i) ws[i]+=ws[i-1];
29         for(int i=n-1; i>=0; --i) sa[--ws[wv[i]]]=y[i];
30         swap(x,y); x[sa[0]]=0; p=1;
31         for(int i=1; i<n; ++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
32     }
33 
34     for(int i=1; i<n; ++i) rank[sa[i]]=i;
35     int k=0;
36     for(int i=0; i<n-1; height[rank[i++]]=k){
37         if(k) --k;
38         for(int j=sa[rank[i]-1]; r[i+k]==r[j+k]; ++k);
39     }
40 }
41 
42 int r[MAXN];
43 char str[MAXN];
44 int main(){
45     int n=0,m;
46     scanf("%s",str);
47     for(int i=0; str[i]; ++i) r[n++]=str[i]-'a'+1;
48     m=n;
49     r[n++]=27;
50     scanf("%s",str);
51     for(int i=0; str[i]; ++i) r[n++]=str[i]-'a'+1;
52     r[n]=0;
53     SA(r,n+1,28);
54     int res=0;
55     for(int i=2; i<=n; ++i){
56         if(sa[i]>m&&sa[i-1]<m || sa[i]<m&&sa[i-1]>m) res=max(res,height[i]);
57     }
58     printf("%d",res);
59     return 0;
60 }

 

posted @ 2016-02-22 20:52  WABoss  阅读(189)  评论(0编辑  收藏  举报