[SAM] Spoj1811 LCS - Longest Common Substring

题意

求两个串 s1 , s2 的最长公共子串。
|s1|,|s2|250000

题解

SAM 模板题。
先建出 s1 SAM ,然后把 s2 放上去跑。
考虑当且处理到第 i 位,若 p 出发有标号为 s2[i] 的边,就直接走,该阶段答案为上次加 1 .
若没有标号为 s2[i] 的边,就走 parent ,直到存在边为止,这个阶段答案为 max(p)+1 ,然后 p 向边 s2[i] 走一步。
走到根都没有的话这个阶段答案就是 0 了。
取所有n个阶段的答案的 max 即可。
实际上 Parent 就是类似失配指针的东西,每次往祖先上跳就是从开头缩减了串长,得到更多向后匹配的机会。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
    node *par,*ch[26]; int _max;
    node(int t1=0){ _max=t1; par=0; memset(ch,0,sizeof(ch)); }
} *root, *last;
typedef node* P_node;
void Extend(int x){
    P_node p=last, np=new node(p->_max+1);
    while(p&&p->ch[x]==0) p->ch[x]=np, p=p->par;
    if(!p) np->par=root; else{
        P_node q=p->ch[x];
        if(q->_max==p->_max+1) np->par=q; else{
            P_node nq=new node(p->_max+1); 
            nq->par=q->par; q->par=nq; np->par=nq;
            memcpy(nq->ch,q->ch,sizeof(q->ch));
            while(p&&p->ch[x]==q) p->ch[x]=nq, p=p->par;
        } 
    }
    last=np;
}
int n,ans,res;
char s[250005];
int main(){
    freopen("spoj1811.in","r",stdin);
    freopen("spoj1811.out","w",stdout);
    scanf("%s",s+1); n=strlen(s+1);
    root=last=new node(0);
    for(int i=1;i<=n;i++) Extend(s[i]-'a');
    scanf("%s",s+1); n=strlen(s+1);
    ans=res=0; P_node p=root;
    for(int i=1;i<=n;i++){
        int x=s[i]-'a';
        if(p->ch[x]) p=p->ch[x], res++; else{
            while(p&&p->ch[x]==0) p=p->par;
            if(!p) p=root, res=0; 
              else res=p->_max+1, p=p->ch[x];
        }
        ans=max(ans,res);
    }
    printf("%d\n",ans);
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值