计算两个字符串(s)和(t)的最长公共子串
由于在一个字符串中出现两次的最长子串一定在相邻两个后缀数组元素的最长公共前缀中取得,也就是高度数组的最大值,所以通过插入一个在两个字符串中不可能出现的字符,将两个字符串连接起来,计算后缀数组和高度数组。其中,分属于字符串(s)和(t)的后缀的高度数组元素的最大值就是最长公共子串的长度
模板题:hdu1403 Longest Common Substring
#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cstring>
#include<string>
#include<sstream>
#include<cmath>
#include<ctime>
#include<algorithm>
#define LL long long
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define pi acos(-1.0)
#define eps 1e-6
#define lowbit(x) x&(-x)
using namespace std;
const int maxn=200010;
int T,n,a[maxn],sa[maxn],rk[maxn],temp[maxn],lcp[maxn],k;
string s,t;
bool cmp_sa(int i,int j){
if(rk[i]!=rk[j])return rk[i]<rk[j];
else{
int ri = i+k<=n?rk[i+k]:-1;
int rj = j+k<=n?rk[j+k]:-1;
return ri<rj;
}
}
void construct_sa(string S,int len, int *sa){
int n=len;
for(int i=0;i<=n;++i){
sa[i]=i;
rk[i]=i<n?s[i]:-1;
}
for(k=1;k<=n;k*=2){
sort(sa,sa+n+1,cmp_sa);
temp[sa[0]]=0;
for(int i=1;i<=n;++i){
temp[sa[i]] = temp[sa[i-1]]+ (cmp_sa(sa[i-1],sa[i])?1:0);
}
for(int i=0;i<=n;++i){
rk[i]=temp[i];
}
}
}
void construct_lcp(string S,int *sa,int *lcp){
int n=S.length();
for(int i=0;i<=n;i++) rk[sa[i]]=i;
int h=0;
lcp[0]=0;
for(int i=0;i<n;i++){
int j=sa[rk[i]-1];
if(h>0) h--;
for(;j+h<n && i+h<n;h++){
if(S[j+h]!=S[i+h]) break;
}
lcp[rk[i]-1]=h;
}
}
void solve(){
int s1=s.length();
s+=' '+t;
n=s.length();
construct_sa(s,n,sa);
construct_lcp(s,sa,lcp);
int ans=0;
for(int i=0;i<n;i++){
if((sa[i]<s1)!=(sa[i+1]<s1)){
ans=max(ans,lcp[i]);
}
}
printf("%d
",ans);
}
int main(){
std::ios::sync_with_stdio(false);
while(getline(cin,s)){
getline(cin,t);
solve();
}
return 0;
}