poj 2774 Long Long Message 后缀数组LCP理解
题意:给两个长度不超过1e5的字符串,问两个字符串的连续公共子串最大长度为多少?
思路:两个字符串连接之后直接后缀数组+LCP,在height中找出max同时满足一左一右即可;
#include<iostream> #include<cstdio> #include<cstring> #include<string.h> #include<algorithm> #include<map> #include<queue> #include<vector> #include<cmath> #include<stdlib.h> #include<time.h> using namespace std; typedef long long ll; const int MAXN = 200007; char s[MAXN],str[MAXN]; int sa[MAXN],t[MAXN],t2[MAXN],c[MAXN],n; void build_sa(int m,int n) // m为字符ASCII码的最大值+1;n = strlen(s) + 1; { int i,*x = t, *y = t2; for(i = 0;i < m; i++) c[i] = 0; for(i = 0;i < n; i++) c[x[i] = s[i]]++; for(i = 1;i < m; i++) c[i] += c[i-1]; for(i = n - 1;i >= 0; i--) sa[--c[x[i]]] = i; for(int k = 1;k <= n;k <<= 1){ int p = 0; for(i = n - k;i < n;i++) y[p++] = i; for(i = 0;i < n;i++) if(sa[i] >= k) y[p++] = sa[i] - k; for(i = 0;i < m;i++) c[i] = 0; for(i = 0;i < n;i++) c[x[y[i]]]++; for(i = 1;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); x[sa[0]] = 0;// 将字符彻底转变为序号; for(i = 1,p = 1;i < n;i++) x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k]?p-1:p++; if(p >= n) break; m = p; } } int rk[MAXN],height[MAXN]; void getHeight() { int i,j,k = 0; for(i = 1;i <= n;i++) rk[sa[i]] = i; // rk[i]:后缀i在sa[]中的下标 for(i = 0;i < n;i++){ if(k) k--; if(rk[i] == 0) continue; j = sa[rk[i] - 1]; while(i+k<n && j+k<n && s[i+k] == s[j+k]) k++; height[rk[i]] = k; // h[i] = height[rk[i]]; h[i] >= h[i-1] - 1; } } int main() { while(scanf("%s%s",s,str) == 2){ int len = strlen(s); s[len] = '#';s[len+1] = '\0'; strcat(s,str); n = strlen(s); s[n] = '#'; build_sa('z'+1,n+1); getHeight(); int ans = -1; for(int i = 2;i <= n;i++) if(height[i] > ans && ((sa[i] < len && sa[i-1] > len) || (sa[i] > len && sa[i-1] < len))) ans = height[i]; printf("%d\n",ans); } return 0; }