SPOJ LCS Longest Common Substring

来源:互联网 发布:seo有何优缺点 编辑:程序博客网 时间:2024/06/06 19:51

SPOJ LCS Longest Common Substring

后缀自动机

题意

给你两个字符串AB,长度250000,求最长公共子串长度。

思路

后缀自动机O(n)算法。对A串建自动机,用B串在上面跑。当前状态设为S,当前字母c,若S有c的转移边,那么S走到新状态,长度加1;否则沿失配边往上走,直到新状态存在c的转移边,长度更新为新状态的最大长度。

代码

#include<bits/stdc++.h>#define M(a,b) memset(a,b,sizeof(a))typedef long long LL;using namespace std;const int MAXL=250005;const int MAXS=26;struct SAM{    int n=0, len, st;    int maxlen[2*MAXL+10], trans[2*MAXL+10][MAXS], slink[2*MAXL+10], endposamu[2*MAXL+10];    int new_state(int _maxlen, int _minlen, int* _trans, int _slink)    {        n++;        maxlen[n]=_maxlen;        for(int i=0; i<MAXS; i++)        {            if(_trans==NULL)                trans[n][i]=0;            else                trans[n][i]=_trans[i];        }        slink[n]=_slink;        return n;    }    int add_char(char ch, int u)    {        int c=ch-'a';        int z=new_state(maxlen[u]+1, -1, NULL, 0);        int v=u;        while(v!=0&&trans[v][c]==0)        {            trans[v][c]=z;            v=slink[v];        }        if(v==0)        {            slink[z]=1;            return z;        }        int x=trans[v][c];        if(maxlen[v]+1==maxlen[x])        {            slink[z]=x;            return z;        }        int y=new_state(maxlen[v]+1, -1, trans[x], slink[x]);        slink[x]=y;        slink[z]=y;        int w=v;        while(w!=0&&trans[w][c]==x)        {            trans[w][c]=y;            w=slink[w];        }        return z;    }    void init()    {        memset(maxlen, 0, sizeof(maxlen));        memset(trans, 0, sizeof(maxlen));        memset(slink, 0, sizeof(maxlen));        memset(endposamu, 0, sizeof(endposamu));        n=0;        st=new_state(0, -1, NULL, 0);    }    void addstring(char s[], int n)    {        int la=st;        for(int i=1;i<=n;i++)        {            la=add_char(s[i], la);        }    }    int match(char t[], int m)    {        int k=st;        int len=0;        int mlen=0;        for(int i=1;i<=m;i++)        {            int now=t[i]-'a';            if(trans[k][now])            {                k=trans[k][now];                len=len+1;            }            else            {                while(!trans[k][now]&&k)                    k=slink[k];                if(!k) k=st, len=0;                else len=maxlen[k], k=trans[k][now], len++;            }            mlen=max(mlen, len);        }        return mlen;    }}sam;char s[250007], t[250007];int main(){    scanf("%s", s+1);    scanf("%s", t+1);    sam.init();    int n=strlen(s+1);    sam.addstring(s, n);    int m=strlen(t+1);    printf("%d\n", sam.match(t, m));    //system("pause");    return 0;}
原创粉丝点击