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 }