SPOJ 1811 Longest Common Substring

http://www.spoj.com/problems/LCS/

题意:求两个串的最长公共子串

用一个串建后缀自动机,另一个串在上面类似于fail树的方式跑

不匹配时到它的parent树上的父节点,相当于保留当前最长匹配后缀

#include<cstdio>
#include<cstring>

using namespace std;

#define N 250002

#define max(x,y) x>y ? x: y

char s1[N],s2[N];

int ch[N<<1][26],fa[N<<1],tot=1;
int len[N<<1];
int last=1,p,np,q,nq;

void extend(int c)
{
    len[np=++tot]=len[last]+1;
    for(p=last;p && !ch[p][c];p=fa[p])     ch[p][c]=np;
    if(!p)  fa[np]=1;
    else
    {
        q=ch[p][c];
        if(len[q]==len[p]+1) fa[np]=q;
        else
        {
            nq=++tot;
            memcpy(ch[nq],ch[q],sizeof(ch[nq]));
            fa[nq]=fa[q];
            fa[q]=fa[np]=nq;
            len[nq]=len[p]+1;
            for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
        }
    }
    last=np;
}

void go()
{
    int l=strlen(s2+1);
    int now=1,ans=0,now_len=0;
    int c;
    for(int i=1;i<=l;++i)
    {
        c=s2[i]-'a';
        while(now && !ch[now][c])
        {
            now=fa[now];
            now_len=len[now];
        }
        if(!now) 
        {
            now_len=0;
            now=1;
        }
        else if(ch[now][c])
        {
            now_len++;
            now=ch[now][c];
            ans=max(ans,now_len);
        }
    }
    printf("%d",ans);
}

int main()
{
    scanf("%s%s",s1+1,s2+1);
    int l=strlen(s1+1);
    for(int i=1;i<=l;++i) extend(s1[i]-'a');
    go();
}
    
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8516883.html