【后缀数组】【poj2774】【 Long Long Message】
題意:
求兩個串的最長連續子串。
我的想法:
? ? ? 枚舉第二個串...在第一個串的后綴數組中二分查找.
? ? ? 復雜度NlogN。最壞情況N^2
題解:
(3)height 數組:定義height[i]=suffix(SA[i-1])和suffix(SA[i])的最長公共前綴,也就是排名相鄰的兩個后綴的最長公共前綴。
(4) h[i]=height[rank[i]],也就是suffix(i)和在它前一名的后綴的最長公共前綴。
(5)LCP(i,j):對正整數i,j 定義LCP(i,j)=lcp(Suffix(SA[i]),Suffix(SA[j]),其中i,j 均為1 至n 的整數。LCP(i,j)也就是后綴數組中第i 個和第j 個后綴的最長公共前綴的長度。其中,函數lcp(u,v)=max{i|u=v},也就是從頭開始順次比較u 和v 的對應字符,對應字符持續相等的最大位置,稱為這兩個字符串的最長公共前綴。
2.2?? 幾個性質
(1)LCP(i,j)=min{height[k]|i+1≤k≤j},也就是說,計算LCP(i,j)等同于詢問一維數組height 中下標在i+1 到j 范圍內的所有元素的最小值。
(1) 最長公共子串。給定兩個字符串A 和B,求最長公共子串。
『解析』先將第二個字符串寫在第一個字符串后面,中間用一個沒有出現過的字符隔開,再求這個新的字符串的后綴數組。當suffix(sa[i-1]) 和suffix(sa[i])不是同一個字符串中的兩個后綴時,max{height[i]}才是滿足條件
..代碼 二段 有一種WA了1萬次才過 #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <ctime> #include <algorithm> #include <iostream> #include <sstream> #include <string> #define oo 0x13131313 using namespace std;/**suffix array*倍增算法 O(n*logn)*待排序數組長度為n,放在0~n-1中,在最后面補一個0*build_sa( ,n+1, );//注意是n+1;*getHeight(,n);*例如:*n = 8;*num[] = { 1, 1, 2, 1, 1, 1, 1, 2, $ };注意num最后一位為0,其他大于0*rank[] = { 4, 6, 8, 1, 2, 3, 5, 7, 0 };rank[0~n-1]為有效值,rank[n]必定為0無效值*sa[] = { 8, 3, 4, 5, 0, 6, 1, 7, 2 };sa[1~n]為有效值,sa[0]必定為n是無效值*height[]= { 0, 0, 3, 2, 3, 1, 2, 0, 1 };height[2~n]為有效值**/ const int MAXN=300000+5; char S1[MAXN],S2[MAXN]; int sa[MAXN]; int t1[MAXN],t2[MAXN],c[MAXN]; int rank[MAXN],height[MAXN]; void build_sa(int s[],int n ,int m) {int i,j,p,*x=t1,*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=0;i<m;i++) c[i]+=c[i-1];for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;for(j=1;j<=n;j<<=1){p=0;for(i=n-j;i<n;i++) y[p++]=i;for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;for(i=0;i<m;i++) c[i]=0;for(i=0;i<n;i++) c[x[y[i]]]++;for(i=0;i<m;i++) c[i]+=c[i-1];for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];swap(x,y);p=1;x[sa[0]]=0;for(i=1;i<n;i++)x[sa[i]]=(y[sa[i-1]]==y[sa[i]])&&(y[sa[i-1]+j]==y[sa[i]+j])?p-1:p++;if(p>=n) break;m=p;} } int s[MAXN]; int len1,len2,ans=0; void getHeight(int s[],int n) {int i,j,k=0;for(i=0;i<=n;i++)rank[sa[i]]=i;for(i=0;i<n;i++){if(k)k--;j=sa[rank[i]-1];while(s[i+k]==s[j+k])k++;height[rank[i]]=k;} } int main() {// freopen("a.in","r",stdin);// freopen("a.out","w",stdout);while(scanf("%s",S1)!=EOF){int ans=0;len1=strlen(S1);scanf("%s",S2);len2=strlen(S2);for(int i=0;i<len1;i++) s[i]=S1[i];s[len1]='$';for(int i=len1+1;i<=len2+len1+1;i++) s[i]=S2[i-len1-1];build_sa(s,len1+len2+2,256);getHeight(s,len1+len2+1);for(int i=2;i<=len1+len2+1;i++){int MAX=max(sa[i-1],sa[i]);int MIN=min(sa[i-1],sa[i]);if(MAX>len1&&MIN<len1){if(ans<height[i])ans=height[i];}}cout<<ans<<endl;} }
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <ctime> #include <algorithm> #include <iostream> #include <sstream> #include <string> #define oo 0x13131313 using namespace std;/**suffix array*倍增算法 O(n*logn)*待排序數組長度為n,放在0~n-1中,在最后面補一個0*build_sa( ,n+1, );//注意是n+1;*getHeight(,n);*例如:*n = 8;*num[] = { 1, 1, 2, 1, 1, 1, 1, 2, $ };注意num最后一位為0,其他大于0*rank[] = { 4, 6, 8, 1, 2, 3, 5, 7, 0 };rank[0~n-1]為有效值,rank[n]必定為0無效值*sa[] = { 8, 3, 4, 5, 0, 6, 1, 7, 2 };sa[1~n]為有效值,sa[0]必定為n是無效值*height[]= { 0, 0, 3, 2, 3, 1, 2, 0, 1 };height[2~n]為有效值**/ const int MAXN=300000+5; char S1[MAXN],S2[MAXN]; int sa[MAXN]; int t1[MAXN],t2[MAXN],c[MAXN]; int rank[MAXN],height[MAXN]; void build_sa(int s[],int n ,int m) {int i,j,p,*x=t1,*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=0;i<m;i++) c[i]+=c[i-1];for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;for(j=1;j<=n;j<<=1){p=0;for(i=n-j;i<n;i++) y[p++]=i;for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;for(i=0;i<m;i++) c[i]=0;for(i=0;i<n;i++) c[x[y[i]]]++;for(i=0;i<m;i++) c[i]+=c[i-1];for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];swap(x,y);p=1;x[sa[0]]=0;for(i=1;i<n;i++)x[sa[i]]=(y[sa[i-1]]==y[sa[i]])&&(y[sa[i-1]+j]==y[sa[i]+j])?p-1:p++;if(p>=n) break;m=p;} } int s[MAXN]; int len1,len2,ans=0; void getHeight(int s[],int n) {int i,j,k=0;for(i=0;i<=n;i++)rank[sa[i]]=i;for(i=0;i<n;i++){if(k)k--;j=sa[rank[i]-1];while(s[i+k]==s[j+k])k++;height[rank[i]]=k;} } int main() {//freopen("a.in","r",stdin);//freopen("a.out","w",stdout);while(scanf("%s",S1)!=EOF){int ans=0;len1=strlen(S1);scanf("%s",S2);len2=strlen(S2);for(int i=0;i<len1;i++) s[i]=S1[i];s[len1]='@';for(int i=len1+1;i<=len2+len1+1;i++) s[i]=S2[i-len1-1];build_sa(s,len1+len2+2,128);getHeight(s,len1+len2+1);for(int i=2;i<=len1+len2+1;i++){if((long long)(sa[i]-len1)*(long long)(sa[i-1]-len1)<0) //乘爆了long long WA了無數發 真是酸爽{if(ans<height[i])ans=height[i];}}cout<<ans<<endl;} }
轉載于:https://www.cnblogs.com/zy691357966/p/5480325.html
總結
以上是生活随笔為你收集整理的【后缀数组】【poj2774】【 Long Long Message】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Broadcom NetXtreme I
- 下一篇: COMPUTER HARDWARE OP