码迷,mamicode.com
首页 > 其他好文 > 详细

后缀自动机专题

时间:2016-05-04 01:07:05      阅读:198      评论:0      收藏:0      [点我收藏+]

标签:

如果不算pre指针的话后缀自动机就是一个DAG,这是它能很方便地进行dp的前提。

而pre指针返回什么呢,返回的就是上一个的前缀包含改结点所代表子串的那个后缀,和AC自动机上的fail指针很像,都是为了匹配。我目前学得不深,看不出和AC自动机的fail指针有什么区别,用起来也几乎一样。

相比于字典树和回文树,后缀自动机每个结点会有多个父结点,可以表示多种子串(从根节点到它的每条路径都是一个子串),因此子串的信息只能在路径中记录,比如长度,而该子串说记录的长度step,则是根结点到它的最远距离,而某个子串的长度就是该代表该子串的路径的长度了,并不一定是某个结点的step。

spoj1811

求两个串的最长公共子串的长度。

对A串建立后缀自动机,对B串进行匹配,如果匹配失败,沿着失败指针往回走到第一个能匹配的位置继续匹配(看起来似曾相识?没错,这不是AC自动机的过程吗。。。),当然如果到根节点还不能继续匹配,那就只有从头再来了。这里随时记录长度更新答案即可。

当然后缀数组也可以做,把两个串拼接起来,求lcp即可。。。然后后缀自动机好快。。。。在spoj上居然60ms过了。。。

技术分享
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=2000100;
const int INF=1e9+10;

struct SAM
{
    int ch[maxn][26];
    int pre[maxn],step[maxn];
    int last,tot;
    void init()
    {
        last=tot=0;
        memset(ch[0],-1,sizeof(ch[0]));
        pre[0]=-1;
        step[0]=0;
    }
    void add(int c)
    {
        c-=a;
        int p=last,np=++tot;
        step[np]=step[p]+1;
        memset(ch[np],-1,sizeof(ch[np]));
        while(~p&&ch[p][c]==-1) ch[p][c]=np,p=pre[p];
        if(p==-1) pre[np]=0;
        else{
            int q=ch[p][c];
            if(step[q]!=step[p]+1){
                int nq=++tot;
                step[nq]=step[p]+1;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                pre[nq]=pre[q];
                pre[q]=pre[np]=nq;
                while(~p&&ch[p][c]==q) ch[p][c]=nq,p=pre[p];
            }
            else pre[np]=q;
        }
        last=np;
    }
    int find(char *s)
    {
        int len=strlen(s);
        int res=0,tmp=0;
        int u=0;
        REP(i,0,len-1){
            int c=s[i]-a;
            if(~ch[u][c]) tmp++,u=ch[u][c];
            else{
                while(~u&&ch[u][c]==-1) u=pre[u];
                if(~u) tmp=step[u]+1,u=ch[u][c];
                else tmp=0,u=0;
            }
            res=max(res,tmp);
        }
        return res;
    }
};SAM sam;
char s[maxn],t[maxn];

void solve()
{
    sam.init();
    int len=strlen(s);
    REP(i,0,len-1) sam.add(s[i]);
    printf("%d\n",sam.find(t));
}

int main()
{
    freopen("in.txt","r",stdin);
    while(~scanf("%s%s",s,t)){
        solve();
    }
    return 0;
}
View Code

 

后缀自动机专题

标签:

原文地址:http://www.cnblogs.com/--560/p/5457023.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!