http://poj.org/problem?id=2774
先做一道小水题提提神
题意:求两个串的最长公共连续子串
可以二分+哈希做
但我要用后缀数组做
两个串拼起来,然后取满足后缀起点分别属于两个串的height数组的最大值
一开始没用特殊字符隔开两个串
他AC了,数据有缺陷呐
第二个串因为最后面是字符串的结束,可以保证公共串不会越界第二个串
但第一个串就没保证了,例如 baa和aaa
然后加了特殊字符'#'隔开,它RE了。。。
因为后缀数组的时候,统计前缀和是 字符-'a'+1,统计1—26,‘#’不满足要求
用 'a'+26,统计1——27
一不留神就出bug,哎
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 200005 char ch[N]; int m,n,k,a[N],v[N],p,q,sa[2][N],rk[2][N],h[N]; void mul(int *sa,int *rk,int *SA,int *RK) { for(int i=1;i<=n;i++) v[rk[sa[i]]]=i; for(int i=n;i;i--) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k; for(int i=n-k+1;i<=n;i++) SA[v[rk[i]]--]=i; for(int i=1;i<=n;i++) RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]]||rk[SA[i]+k]!=rk[SA[i-1]+k]); } void presa() { p=0; q=1; for(int i=1;i<=27;++i) v[i]=0; for(int i=1;i<=n;i++) v[a[i]]++; for(int i=1;i<=27;i++) v[i]+=v[i-1]; for(int i=1;i<=n;i++) sa[p][v[a[i]]--]=i; for(int i=1;i<=n;i++) rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i-1]]!=a[sa[p][i]]); for(k=1;k<n;k<<=1,swap(p,q)) mul(sa[p],rk[p],sa[q],rk[q]); for(int i=1,k=0;i<=n;i++) { int j=sa[p][rk[p][i]-1]; while(a[i+k]==a[j+k]) k++; h[rk[p][i]]=k;if(k) k--; } } void solve() { int ans=0,t1,t2; for(int i=2;i<=n;++i) { t1=sa[p][i]<=m; t2=sa[p][i-1]<=m; if(t1+t2==1) ans=max(ans,h[i]); } printf("%d",ans); } int main() { scanf("%s",ch+1); m=strlen(ch+1); ch[++m]='a'+26; scanf("%s",ch+m+1); n=strlen(ch+1); for(int i=1;i<=n;i++) a[i]=ch[i]-'a'+1; presa(); solve(); }