题意
求两个串
s1
,
s2
的最长公共子串。
|s1|,|s2|≤250000
题解
SAM
模板题。
先建出
s1
的
SAM
,然后把
s2
放上去跑。
考虑当且处理到第
i
位,若
若没有标号为
走到根都没有的话这个阶段答案就是
0
了。
取所有n个阶段的答案的
实际上
Parent
就是类似失配指针的东西,每次往祖先上跳就是从开头缩减了串长,得到更多向后匹配的机会。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
node *par,*ch[26]; int _max;
node(int t1=0){ _max=t1; par=0; memset(ch,0,sizeof(ch)); }
} *root, *last;
typedef node* P_node;
void Extend(int x){
P_node p=last, np=new node(p->_max+1);
while(p&&p->ch[x]==0) p->ch[x]=np, p=p->par;
if(!p) np->par=root; else{
P_node q=p->ch[x];
if(q->_max==p->_max+1) np->par=q; else{
P_node nq=new node(p->_max+1);
nq->par=q->par; q->par=nq; np->par=nq;
memcpy(nq->ch,q->ch,sizeof(q->ch));
while(p&&p->ch[x]==q) p->ch[x]=nq, p=p->par;
}
}
last=np;
}
int n,ans,res;
char s[250005];
int main(){
freopen("spoj1811.in","r",stdin);
freopen("spoj1811.out","w",stdout);
scanf("%s",s+1); n=strlen(s+1);
root=last=new node(0);
for(int i=1;i<=n;i++) Extend(s[i]-'a');
scanf("%s",s+1); n=strlen(s+1);
ans=res=0; P_node p=root;
for(int i=1;i<=n;i++){
int x=s[i]-'a';
if(p->ch[x]) p=p->ch[x], res++; else{
while(p&&p->ch[x]==0) p=p->par;
if(!p) p=root, res=0;
else res=p->_max+1, p=p->ch[x];
}
ans=max(ans,res);
}
printf("%d\n",ans);
}