【POJ2774】Long Long Message(字尾陣列求Height陣列)
阿新 • • 發佈:2018-12-04
大致題意: 求兩個字串中最長公共子串的長度。
關於字尾陣列
關於\(Height\)陣列的概念以及如何用字尾陣列求\(Height\)陣列詳見這篇部落格:字尾陣列入門(二)——Height陣列與LCP。
大致思路
由於字尾陣列是處理一個字串的,因此我們第一步自然是將這兩個字串拼在一起,並在中間加一個不可能出現的字元,例如\(\%\)。
然後我們用字尾陣列求出其\(Height\)陣列。
注意一個性質,答案肯定是按字典序排名後相鄰字尾的\(LCP\)值中的最大值。
因此,我們只要列舉\(i\),判斷字尾\(_{SA_i}\)與字尾\(_{SA_{i-1}}\) 的起始字元是否在同一個字串內,然後更新答案即可。
回顧\(Height\)陣列定義就是\(Height_i=LCP(i,i-1)\)。
因此我們其實不用再額外去求相鄰字尾的\(LCP\),直接呼叫\(Height\)陣列即可。
具體實現詳見程式碼。
程式碼
#include<cstdio> #include<cstring> #define N 100000 #define Gmax(x,y) (x<(y)&&(x=(y))) using namespace std; int n,m;char s[(N<<1)+5]; class Class_SuffixArray//字尾陣列 { private: int n,rk[(N<<1)+5],pos[(N<<1)+5],tot[(N<<1)+5]; inline void RadixSort(int S) { register int i; for(i=0;i<=S;++i) tot[i]=0; for(i=1;i<=n;++i) ++tot[rk[i]]; for(i=1;i<=S;++i) tot[i]+=tot[i-1]; for(i=n;i;--i) SA[tot[rk[pos[i]]]--]=pos[i]; } inline void GetSA(char *s) { register int i,k,cnt=0,Size=122; for(n=strlen(s),i=1;i<=n;++i) rk[pos[i]=i]=s[i-1]; for(RadixSort(Size),k=1;cnt<n;k<<=1) { for(Size=cnt,cnt=0,i=1;i<=k;++i) pos[++cnt]=n-k+i; for(i=1;i<=n;++i) SA[i]>k&&(pos[++cnt]=SA[i]-k); for(RadixSort(Size),i=1;i<=n;++i) pos[i]=rk[i]; for(rk[SA[1]]=cnt=1,i=2;i<=n;++i) rk[SA[i]]=(pos[SA[i-1]]^pos[SA[i]]||pos[SA[i-1]+k]^pos[SA[i]+k])?++cnt:cnt; } } inline void GetHeight(char *s) { register int i,j,k=0; for(i=1;i<=n;++i) rk[SA[i]]=i; for(i=1;i<=n;++i) { if(!(rk[i]^1)) continue; k&&--k,j=SA[rk[i]-1]; while(i+k<=n&&j+k<=n&&!(s[i+k-1]^s[j+k-1])) ++k; Height[rk[i]]=k; } } public: int SA[(N<<1)+5],Height[(N<<1)+5]; inline void Init(char *s) {GetSA(s),GetHeight(s);} }S; int main() { register int i,ans=0; scanf("%s",s),n=strlen(s),s[n]='%',scanf("%s",s+n+1),m=strlen(s+n+1); for(S.Init(s),i=1;i<=n+m;++i) if((S.SA[i]<n)^(S.SA[i-1]<n)) Gmax(ans,S.Height[i]);//如果相鄰兩個字尾的起始字元不在同一個字串內,就更新答案 return printf("%d",ans),0; }