POJ-2774 后缀数组基础题
题意:求两个字符串的最长公共子串。
总结:搞了半天还是不太理解,看着大神博客强行敲的。。而且还看到有hash+二分做的。
// POJ-2774 #include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<queue> #include<stack> #include<map> #include<bitset> #include<vector> #include<set> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define F(i,a,b) for (int i=a;i<b;i++) #define FF(i,a,b) for (int i=a;i<=b;i++) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f typedef long long ll; const int N = 3e5+10; char str[N], str1[N]; //这些应该可以做模板了。。 int wa[N], wb[N], wsf[N], wv[N], sa[N]; int rankn[N], height[N], s[N]; int cmp(int *r, int a, int b, int k) { return r[a]==r[b] && r[a+k]==r[b+k]; } void Getsa(int *r, int *sa, int n, int m) { int i, j, p, *x=wa, *y=wb, *t; F(i,0,m) wsf[i]=0; F(i,0,n) wsf[x[i]=r[i]]++; F(i,1,m) wsf[i]+= wsf[i-1]; for(i=n-1; i>=0; i--) sa[--wsf[x[i]]]=i; p=1, j=1; for( ; p<n; j*=2, m=p) { for(p=0, i=n-j; i<n; i++) y[p++]=i; F(i,0,n) if(sa[i]>=j) y[p++]=sa[i]-j; F(i,0,n) wv[i]=x[y[i]]; F(i,0,m) wsf[i]=0; F(i,0,n) wsf[wv[i]]++; F(i,1,m) wsf[i]+= wsf[i-1]; for(i=n-1; i>=0; i--) sa[--wsf[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 n) { int i, j, k=0; FF(i,1,n) rankn[sa[i]]=i; F(i,0,n) { if(k) k--; else k=0; j=sa[rankn[i]-1]; while(r[i+k]==r[j+k]) k++; height[rankn[i]]=k; } } int main() { while(~scanf("%s%s", str, str1)) { int n=0, len=strlen(str); F(i,0,len) s[n++]= str[i]-'a'+1; s[n++]=28; len=strlen(str1); F(i,0,len) s[n++]= str1[i]-'a'+1; s[n]=0; //把两个字符串并到一起,中间和结尾加上标识符 Getsa(s, sa, n+1, 30); Getheight(s, n); int maxn=0, pos=0; len=strlen(str); F(i,2,n) if(height[i]>maxn) { //找出一个height值最大并且i与i-1的sa值分别在两串字符中 if(0<=sa[i-1] && sa[i-1]<len && len<sa[i]) maxn=height[i]; if(0<=sa[i] && sa[i]<len && len<sa[i-1]) maxn=height[i]; } printf("%d\n", maxn); } return 0; }