SP1811 LCS - Longest Common Substring
用 sam 进行字符串匹配,建 s 的 sam,然后用 t 在 s 的 sam 上进行匹配,匹配过程中,沿着 Next 转移往下走,如果失配,则沿着 link 链接往上跳,因为 link 链接是该节点的后缀,所以这样跳就不会有遗漏,而且均摊下来跳后缀链接的总复杂度为(O(n))因此不会超时。
// Created by CAD
#include <bits/stdc++.h>
using namespace std;
const int maxn=(2e5+5e4+5)*2;
namespace sam{
int len[maxn],link[maxn],Next[maxn][26];
int sz,last;
void init(){ //记得初始化
sz=last=0;
len[0]=0,link[0]=-1;
}
void insert(char c){ //插入字符
int now=++sz;
len[now]=len[last]+1;
int p=last;
while(~p&&!Next[p][c-'a']){
Next[p][c-'a']=now;
p=link[p];
}
if(p==-1) link[now]=0;
else{
int q=Next[p][c-'a'];
if(len[p]+1==len[q]) link[now]=q;
else{
int clone=++sz;
len[clone]=len[p]+1;
memcpy(Next[clone],Next[q],sizeof(Next[q]));
link[clone]=link[q];
while(~p&&Next[p][c-'a']==q){
Next[p][c-'a']=clone;
p=link[p];
}
link[q]=link[now]=clone;
}
}
last=now;
}
int solve(char *s,char *t){
int ans=0;
int op=0,last=-1;
int slen=strlen(s),tlen=strlen(t);
int now=0;
while(op<tlen){
int temp=0;
while(op<tlen&&Next[now][t[op]-'a']){//如果匹配则沿着转移走下去
now=Next[now][t[op]-'a'];
temp=op-last;
ans=max(ans,temp);
op++;
}
if(temp==0) op++,last++;
while(~link[now]&&!Next[now][t[op]-'a'])
//一旦失配,则沿着后缀链接往上跳,直到跳到0或者再次匹配
now=link[now];
last+=temp-len[now];
}
return ans;
}
}
char s[maxn],t[maxn];
int main() {
sam::init();
scanf("%s%s",s,t);
int slen=strlen(s);
for(int i=0;i<slen;++i) sam::insert(s[i]);
printf("%d
",sam::solve(s,t));
return 0;
}