【后缀自动机】[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);
}
posted @ 2015-12-29 13:23  outer_form  阅读(107)  评论(0编辑  收藏  举报