【后缀自动机】[SPOJLCS]Longest Common Substring
题目大意
给两个长度小于100000的字符串A和B,求出他们的最长公共连续子串。
分析
后缀自动机基础题。
根据A串构造后缀自动机,然后用B串进行匹配。假设前匹配到了s[i],l为上次停留的节点,如果l有儿子s[i],len++,l=l->ch[s[i]],否则,沿着失配边走到当前第一个有儿子s[i]的节点a,len=a节点所表示的最大的字串长度+1,l=a->ch[s[i]];
ans即为过程中匹配到的最长的字串。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 250000
#define MAXC 26
using namespace std;
char s[MAXN+10];
int n,ans;
struct node{
int len;
node *ch[MAXC],*fail;
}tree[MAXN*2+10],*tcnt=tree,*root=tcnt,*l=root;
void insert(char c){
c-='a';
node *p=l,*np=++tcnt,*q,*nq;
np->len=p->len+1;
l=np;
while(p&&!p->ch[c])
p->ch[c]=np,p=p->fail;
if(!p)
np->fail=root;
else{
q=p->ch[c];
if(q->len==p->len+1)
np->fail=q;
else{
nq=++tcnt;
*nq=*q;
nq->len=p->len+1;
q->fail=nq;
np->fail=nq;
while(p&&p->ch[c]==q)
p->ch[c]=nq,p=p->fail;
}
}
}
void read(){
scanf("%s",s);
n=strlen(s);
int i;
for(i=0;i<n;i++)
insert(s[i]);
scanf("%s",s);
n=strlen(s);
}
void solve(){
int i,len=0;
node *p=root;
for(i=0;i<n;i++){
s[i]-='a';
if(p->ch[s[i]])
p=p->ch[s[i]],len++;
else{
while(p&&!p->ch[s[i]])
p=p->fail;
if(!p)
p=root,len=0;
else
len=p->len+1,p=p->ch[s[i]];
}
ans=max(ans,len);
}
}
int main()
{
read();
solve();
printf("%d\n",ans);
}