SPOJ 1811 Longest Common Substring(SAM)

转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove 

题目:求出两个串的LCS

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

先将A串建立 SAM。

然后把B串在SAM上跑一遍

如果当前匹配最长为l,当前状态存在son[b[i]],则说明可以继续匹配l++

否则沿着pre找。
线性的,比SA确实很快点,不过DC3应该能过

#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<queue>
#define inf 100000005
#define M 40
#define N 510005
#define maxn 300005
#define eps 1e-10
#define zero(a) fabs(a)<eps
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define pb(a) push_back(a)
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define LL unsigned long long
#define MOD 1000000007
#define lson step<<1
#define rson step<<1|1
#define sqr(a) ((a)*(a))
#define Key_value ch[ch[root][1]][0]
#define test puts("OK");
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
struct SAM
{
    SAM *pre,*son[26];
    int len,g;
}que[N],*root,*tail;
int tot;
void add(int c,int l)
{
    SAM *p=tail,*np=&que[tot++];
    np->len=l;tail=np;
    while(p&&p->son[c]==NULL) p->son[c]=np,p=p->pre;
    if(p==NULL) np->pre=root;
    else
    {
        SAM *q=p->son[c];
        if(p->len+1==q->len) np->pre=q;
        else
        {
            SAM *nq=&que[tot++];
            *nq=*q;
            nq->len=p->len+1;
            np->pre=q->pre=nq;
            while(p&&p->son[c]==q) p->son[c]=nq,p=p->pre;
        }
    }
}
char a[N/2],b[N/2];
int main()
{
    scanf("%s%s",a,b);
    tot=0;
    root=tail=&que[tot++];
    for(int i=0;a[i];i++) add(a[i]-'a',i+1);
    SAM *p=root;
    int ans=0;
    for(int i=0,l=0;b[i];i++,ans=max(ans,l))
    {
        int c=b[i]-'a';
        if(p->son[c]) p=p->son[c],l++;
        else
        {
            while(p&&p->son[c]==NULL) p=p->pre;
            if(p==NULL) p=root,l=0;
            else l=p->len+1,p=p->son[c];
        }
    }
    printf("%d\n",ans);
    return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值