Long Long Message
题意:
求两个字符串的最长连续公共子串。
分析:
后缀树组的模板题。首先明确一点,这个最长连续公共子串s一定是这两个字符串中的某个字符的后缀的最长公共前缀(假设s首字母在两个字符串中的对应位置为i,j,那么i,j后缀的最长公共前缀就是s)。那么当我们将这两个字符串拼接在一起后,求得任意两个字符(位于不同字符串)的后缀的最长公共前缀中的最优解即是答案。而求后缀的最长公共前缀就是求后缀数组中height数组,所以我们只需要算出height数组后,判断对应的两个字符是否位于不同字符串即可。
代码:
倍增算法
#include <map> #include <queue> #include <math.h> #include <string> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) const int maxn=2e6+100; int s[maxn]; char str1[maxn],str2[maxn]; int sa[maxn],height[maxn],Rank[maxn]; namespace Suffix { int wa[maxn],wb[maxn],wv[maxn],wt[maxn]; int cmp(int *r,int a,int b,int k) { return r[a]==r[b]&&r[a+k]==r[b+k]; } void da(int *r,int *sa,int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i=0; i<m; i++) wt[i]=0; for(i=0; i<=n; i++) wt[x[i]=r[i]]++; for(i=1; i<m; i++) wt[i]+=wt[i-1]; for(i=n; i>=0; i--) sa[--wt[x[i]]]=i; p=1; j=1; for(; p<=n; j*=2,m=p) { for(p=0,i=n+1-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<=n; i++) wv[i]=x[y[i]]; for(i=0; i<m; i++) wt[i]=0; for(i=0; i<=n; i++) wt[wv[i]]++; for(i=1; i<m; i++) wt[i]+=wt[i-1]; for(i=n; i>=0; i--) sa[--wt[wv[i]]]=y[i]; t=x; x=y; y=t; x[sa[0]]=0; for(p=1,i=1; i<=n; i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++; } } void getheight(int *r,int* sa,int n) { int i,j,k=0; for(i=1; i<=n; i++) Rank[sa[i]]=i; for(i=0; i<n; i++) { if(k) k--; else k=0; j=sa[Rank[i]-1]; while(r[i+k]==r[j+k]) k++; height[Rank[i]-1]=k; } } }; int main() { // freopen("in.txt","r",stdin); while(scanf("%s%s",str1,str2)!=EOF) { int len1=strlen(str1); int len2=strlen(str2); for(int i=0;i<len1;i++){ s[i]=str1[i]-'a'+1; } s[len1]=30; for(int i=0;i<len2;i++){ s[i+len1+1]=str2[i]-'a'+1; } s[len1+len2+1]=0; int sz=len1+len2+1; Suffix::da(s,sa,sz,31); Suffix::getheight(s,sa,sz); int maxlen=0; for(int i=2;i<sz;i++){ if(height[i-1]>maxlen){ if((ll)(sa[i-1]-len1)*(sa[i]-len1)<0){ maxlen=height[i-1]; } } } printf("%d ",maxlen); } return 0; }
dc3算法
#include <map> #include <queue> #include <math.h> #include <string> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) const int maxn=2e6+100; int s[maxn]; char str1[maxn],str2[maxn]; int sa[maxn],height[maxn],Rank[maxn]; namespace Suffix { int wa[maxn],wb[maxn],wv[maxn],wt[maxn]; #define F(x) ((x)/3+((x)%3==1?0:tb)) #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2) int c0(int r[], int a, int b) { return r[a]==r[b] && r[a+1]==r[b+1] && r[a+2]==r[b+2]; } int c12(int k, int r[], int a, int b) { if(k==2) return r[a]<r[b] || (r[a]==r[b] && c12(1,r,a+1,b+1)); else return r[a]<r[b] || (r[a]==r[b] && wv[a+1]<wv[b+1]); } void Rsort(int r[], int a[], int b[], int n, int m){ int i; for(i = 0; i < n; ++i) wv[i] = r[a[i]]; for(i = 0; i < m; ++i) wt[i] = 0; for(i = 0; i < n; ++i) ++wt[wv[i]]; for(i = 1; i < m; ++i) wt[i] += wt[i-1]; for(i = n-1; i >= 0; --i) b[--wt[wv[i]]] = a[i]; } void dc3(int r[], int sa[], int n, int m){ int i, j, *rn = r+n, *san = sa+n, ta=0, tb=(n+1)/3, tbc=0, p; r[n] = r[n+1] = 0; for(i = 0; i < n; ++i) if(i%3!=0) wa[tbc++] = i; Rsort(r+2, wa, wb, tbc, m); Rsort(r+1, wb, wa, tbc, m); Rsort(r, wa, wb, tbc, m); rn[F(wb[0])] = 0; p = 1; for(i = 1; i < tbc ; ++i) rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p-1 : p++; if(p < tbc) dc3(rn, san, tbc, p); else for(i=0;i<tbc;i++) san[rn[i]] = i; for(i = 0; i < tbc; ++i) if(san[i]<tb) wb[ta++] = san[i]*3; if(n%3==1) wb[ta++]=n-1; Rsort(r, wb, wa, ta, m); for(i = 0; i < tbc; ++i) wv[wb[i] = G(san[i])] = i; for(i=0,j=0,p=0; i<ta && j<tbc; p++) sa[p] = c12(wb[j]%3, r, wa[i], wb[j]) ? wa[i++] : wb[j++]; while(i < ta) sa[p++] = wa[i++]; while(j < tbc) sa[p++] = wb[j++]; } void getheight(int *r,int* sa,int n) { int i,j,k=0; for(i=1; i<=n; i++) Rank[sa[i]]=i; for(i=0; i<n; i++) { if(k) k--; else k=0; j=sa[Rank[i]-1]; while(r[i+k]==r[j+k]) k++; height[Rank[i]-1]=k; } } }; int main() { // freopen("in.txt","r",stdin); while(scanf("%s%s",str1,str2)!=EOF) { int len1=strlen(str1); int len2=strlen(str2); for(int i=0;i<len1;i++){ s[i]=str1[i]-'a'+1; } s[len1]=30; for(int i=0;i<len2;i++){ s[i+len1+1]=str2[i]-'a'+1; } s[len1+len2+1]=0; int sz=len1+len2+1; Suffix::dc3(s,sa,sz+1,31); Suffix::getheight(s,sa,sz); int maxlen=0; for(int i=2;i<sz;i++){ if(height[i-1]>maxlen){ if((ll)(sa[i-1]-len1)*(sa[i]-len1)<0){ maxlen=height[i-1]; } } } printf("%d ",maxlen); } return 0; }