SPOJ LCS

求两个串的最长公共字串

后缀自动机模板题

#include<bits/stdc++.h>
using namespace std;

const int maxn = 251234,mlen = 26;
int toid(char c){ return c - 'a'; }

struct Node{
    int len,fa,nex[mlen];
    Node(int _len = 0){
        len = _len;
        memset(nex,fa=-1,sizeof(nex));
    }
    void copy(const Node & v){
        for(int i=0;i<mlen;i++) 
            nex[i] = v.nex[i];
        fa = v.fa;
    }
    void out(){
        printf("fa = %2d len = %d ",fa,len);
        for(int i=0;i<4;i++){
            printf("(%c %2d)",i+'a',nex[i]);
        }
        puts("");
    }
}node[maxn*2]; 
int _cnt;

int newNode(int len){
    node[_cnt] = Node(len);
    return _cnt++;
}
int root,omega; //在一些模板中也用last作为变量名,这里取omega作为最后一个的意思
void init(){
    _cnt = 0;
    root = omega = newNode(0);
}
void extend(int x){
    int ox = newNode(node[omega].len+1);
    while(omega != -1 && node[omega].nex[x] == -1){
        node[omega].nex[x] = ox;
        omega = node[omega].fa;
    }
    if(omega == -1){
        node[ox].fa = root;
    }
    else{
        int omegax = node[omega].nex[x]; //omegax是omega后面添加x所转移到的状态
        if(node[omega].len + 1 == node[omegax].len){
            node[ox].fa = omegax;
        } 
        else{
            int megax = newNode(node[omega].len+1); //megax是omegax所分裂出来的一个后缀状态
            node[megax].copy(node[omegax]);
            node[ox].fa = node[omegax].fa = megax;
            while(omega != -1 && node[omega].nex[x] == omegax){
                node[omega].nex[x] = megax;
                omega = node[omega].fa;
            }
        }
    }
    omega = ox;
}

void build(char *arr){
    init();
    for(int i=0;arr[i];i++){
        extend(toid(arr[i]));
    }
}


int run(char *arr){
    int st = root;
    int ret = 0,len = 0;
    auto tox = [&](int s,int i){return node[s].nex[toid(arr[i])];};
    for(int i=0;arr[i];i++){
        if(tox(st,i) != -1){
            len++;
            ret = max(ret,len);
            st = tox(st,i);
        }
        else{
            while(st != -1 && tox(st,i) == -1){
                st = node[st].fa;
            }
            if(st == -1){
                len = 0;
                st = 0;
            }
            else {
                len = node[st].len+1;
                st = tox(st,i);
                ret = max(ret,len);
            }
        }
    }
    return ret;
}

char inp[maxn];

int main(){
    while(~scanf("%s",inp)){
        build(inp);
        scanf("%s",inp);
        printf("%d\n",run(inp));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值