SPOJ - LCS Longest Common Substring 后缀自动机

求两个串 的最长公共子串
后缀自动机sam 的模板题

#include<bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define sf scanf
#define pf printf
#define mem(a,b) memset(a,b,sizeof(a));
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define MP make_pair
#define ULL unsigned long long
#define LL   long long
#define inf 0x3f3f3f3f
#define md ((ll+rr)>>1)
#define ls (i<<1)
#define rs (ls|1)
#define eps 1e-5
#define N 2050
#define ree freopen("in.txt","r",stdin);
#define bug pf("----------------");
const int mxn=300002;
struct node{
    node*par,*go[26];
    int val;
}p[mxn*4];

int sz;
node *creat(int val){
    ++sz;
    p[sz].val=val;
    p[sz].par=0;
    mem(p[sz].go,0);
    return &p[sz];
}
node*root,*lst;
void extend(int w){
    node*p=lst;
    node*np=creat(p->val+1);
    while(p&&p->go[w]==0)
        p->go[w]=np,p=p->par;
    if(p==0)np->par=root;
    else{
        node*q=p->go[w];
        if(p->val+1==q->val)
            np->par=q;
        else{
            node*nq=creat(p->val+1);
            memcpy(nq->go,q->go,sizeof(q->go));
            nq->par=q->par;
            q->par=nq;
            np->par=nq;
            while(p&&p->go[w]==q){
                p->go[w]=nq,p=p->par;
            }
        }
    }
    lst=np;
}
char a[mxn],b[mxn];

int main(){
    while(~sf("%s%s",a,b)){
        sz=0;
        root=lst=creat(0);
        for(int i=0;a[i];++i)
            extend(a[i]-'a');
        int ans=0;
        node*p=root;
        int len=0;
        for(int i=0;b[i];++i){
            int c=b[i]-'a';
            if(p->go[c]!=NULL){
                p=p->go[c];
                ++len;
                ans=max(ans,len);
            }
            else{
                while(p&&p->go[c]==0)
                    p=p->par;
                if(!p)
                    p=root,len=0;
                else{
                    len=p->val+1;
                    p=p->go[c];
                    ans=max(ans,len);
                }
            }
        }
        pf("%d\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值