1. 程式人生 > >後綴數組的使用心得——POJ2774 最長連續公共子串

後綴數組的使用心得——POJ2774 最長連續公共子串

應用 amp poj 連續 vector rank name include out

對於這道題,將兩個字符串直接合並成為一個字符串,分別記錄連個字符串結束的位置。

首先,應用黑暗聖典的模板,我們可以順利得到height,rank,sa三個數組。

之後直接掃描1-n所有的位置,選出來一個,符合“兩者都在不同子串的最大長度即可”。

此時我們會發現,sa數組記錄了每個子串開頭的位置,可以用於判斷。

#include<iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<vector>
#include<algorithm>
using
namespace std; const long long MAXN=200233; const long long INF=1e8+233; char s[MAXN]; int sa[MAXN],t[MAXN],t2[MAXN],c[MAXN],n; int rankk[MAXN],height[MAXN]; void getHeight() { int k=0; for(int i=0;i<n;++i)rankk[sa[i]]=i; for(int i=0;i<n;++i) { if(k)k--; int j=sa[rankk[i]-1
]; while(s[i+k]==s[j+k])k++; height[rankk[i]]=k; } } void build_sa(int m) { int i,*x=t,*y=t2; for(int i=0;i<m;++i)c[i]=0; for(int i=0;i<n;++i)c[x[i]=s[i]]++; for(int i=1;i<m;++i)c[i]+=c[i-1]; for(int i=n-1;i>=0;--i)sa[--c[x[i]]]=i; for(int k=1
;k<=n;k*=2) { int p=0; for(int i=n-k;i<n;++i)y[p++]=i; for(int i=0;i<n;++i)if(sa[i]>=k)y[p++]=sa[i]-k; for(int i=0;i<m;++i)c[i]=0; for(int i=0;i<n;++i)c[x[y[i]]]++; for(int i=0;i<m;++i)c[i]+=c[i-1]; for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1;x[sa[0]]=0; for(int i=1;i<n;++i) { x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; } if(p>=n)break; m=p; } } int main() { // cin.sync_with_stdio(false); scanf("%s",s); int len=strlen(s); scanf("%s",s+len); int len2=strlen(s); n=len2+1; build_sa(233); getHeight(); int maxx=-1; for(int i=1;i<n;++i) { // cout<<height[i]<<ends<<s+sa[i]<<endl; if((sa[i]>=len&&sa[i-1]<len)||(sa[i]<len&&sa[i-1]>=len))maxx=max(maxx,height[i]); } cout<<maxx<<"\n"; // cout<<s<<endl; // cout<<len<<ends<<len2<<endl; // return 0; }

後綴數組的使用心得——POJ2774 最長連續公共子串