SPOJ 1811 Longest Common Substring 后缀自动机

模板来源:http://www.neroysq.com/?p=76

思路:http://blog.sina.com.cn/s/blog_7812e98601012dfv.html

题意就是求两个字符串的最长公共子串,串长最大250000。

以串A构建一个后缀自动机,用串B来匹配。枚举串B的每一位B[i]即考虑串B中所有以B[i]为结尾的子串,维护的值为以B[i]为末尾能匹配的最大长度tmpL。

假设走到B[i]时已经匹配好的串为str,如果当前节点有B[i]这个儿子,直接向下走,++tmpL。

如果没有,沿着fail指针向前回退,直到找到一个有B[i]儿子的节点。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>

using namespace std;

const int MAXN = 250010;
const int SigmaSize = 26;

struct sanode
{
    sanode *f, *ch[SigmaSize];
    int l;
};

struct Suffix_Automaton
{
    sanode pool[ ( MAXN << 1 ) + 20 ];
    sanode *init;
    sanode *tail;
    int tot;

    void Clear()
    {
        tot = 0;
        init = pool;
        tail = init;
        return;
    }

    void Insert( int c )
    {
        sanode *q = pool + ( ++tot ), *p = tail;
        q->l = p->l + 1;
        for ( ; p && !p->ch[c]; p = p->f ) p->ch[c] = q;
        tail = q;
        if ( !p ) q->f = init;
        else
        {
            if ( p->ch[c]->l == p->l + 1 ) q->f = p->ch[c];
            else
            {
                sanode *r = pool + ( ++tot ), *u = p->ch[c];
                *r = *u;
                r->l = p->l + 1;
                u->f = q->f = r;
                for ( ; p && p->ch[c] == u; p = p->f ) p->ch[c] = r;
            }
        }
    }
};

char str[MAXN + 20];
Suffix_Automaton SAM;

int main()
{
    int len;
    scanf( "%s", str + 1 );

    SAM.Clear();
    len = strlen( str + 1 );
    for ( int i = 1; i <= len; ++i )
        SAM.Insert( str[i] - 'a' );
    sanode *p = SAM.init;
    scanf( "%s", str + 1 );
    len = strlen( str + 1 );
    int tmpL = 0, ans = 0;
    for ( int i = 1; i <= len; ++i )
    {
        if ( p->ch[ str[i] - 'a' ] )   //可以向下匹配的时候就继续向下匹配
            p = p->ch[ str[i] - 'a' ], ++tmpL;
        else  //如果当前p没有str[i]这个孩子
        {
            while ( p && !p->ch[ str[i] - 'a' ] ) 
          p = p->f; //沿着fail指针向前找,直到找到有str[i]儿子的结点,或者到根节点 if( p ) //如果能找到一个有str[i]儿子的节点 { tmpL = p->l + 1; p = p->ch[ str[i] - 'a' ]; } else //直到回到根也没有找到 { p = SAM.init; tmpL = 0; } } ans = max( ans, tmpL ); } printf( "%d ", ans ); return 0; }
原文地址:https://www.cnblogs.com/GBRgbr/p/3236961.html