• 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; }
  • 相关阅读:
    [SDOI2008]Sue的小球
    【洛谷P2611】小蓝的好友
    【YbtOJ#20051】简单游走
    【洛谷P3338】力
    【洛谷P3803】【模板】多项式乘法(FFT)
    【YbtOJ#10053】合影队形
    【YbtOJ#20056】树上取模
    【洛谷P1919】【模板】A*B Problem升级版
    初赛练习总结
    【洛谷P3723】礼物
  • 原文地址:https://www.cnblogs.com/GBRgbr/p/3236961.html
Copyright © 2020-2023  润新知