SPOJ1811 后缀自动机入门

题目链接点我点我:-)

题目描述
求两个字符串的最长公共子串的长度,字符串长度小于等于5105

输入格式
两行即两个字符串

输出格式
一个整数,表示两个字符串的最长公共子串的长度

思路
后缀自动机裸题,入门的一个好的讲解:传送门

感想
还是有一些地方不是很理解,特别是匹配的时候有点乱(关于step的问题)
还有一个同学的习题锦集,可以去做一下:传送门
(ps: 下方程序中的Query函数并没有用)

代码

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

using namespace std;

#define For(i, a, b) for(int i = (a); i <= (int)(b); ++i)
#define N (500000+5)

struct Suffix_Automaton{
    char s[N];
    int son[N][26], pre[N], step[N], root, last, Tot;

    void Insert(char ch){
        ch -= 'a';

        int p = last, np = ++Tot;
        step[np] = step[last]+1; last = np;

        for(;p&&!son[p][ch]; p=pre[p]) son[p][ch] = np;
        if(!p) pre[np] = root;
        else{
            if(step[p]+1 == step[son[p][ch]]) pre[np] = son[p][ch];
            else{
                int q = son[p][ch], nq = ++Tot;

                pre[nq] = pre[q]; step[nq] = step[p]+1;
                For(i, 0, 25) son[nq][i] = son[q][i];
                pre[q] = pre[np] = nq;
                for(;son[p][ch]==q; p=pre[p]) son[p][ch] = nq;
            }
        }
    }

    int Query(char *s){
        int nc, now = root, len = strlen(s);
        For(i, 0, len-1){
            nc = s[i]-'a';
            if(!son[now][nc]) return i;
            now = son[now][nc];
        }
        return len;
    }
}sat;

char s1[N], s2[N];

int main(){
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif

    sat.root = sat.last = ++sat.Tot;
    scanf("%s%s", s1, s2);

    int len1 = strlen(s1), len2 = strlen(s2);
    For(i, 0, len1-1) sat.Insert(s1[i]);

    int ans = 0, len = 0, now = sat.root;
    char ch;
    For(i, 0, len2-1){
        ch = s2[i]-'a';

        if(sat.son[now][ch]) ++len, now = sat.son[now][ch];
        else{
            while(now && !sat.son[now][ch]) now = sat.pre[now];
            if(!now) now = sat.root, len = 0;
            else len = sat.step[now]+1, now = sat.son[now][ch]; 
        }
        ans = max(ans, len);
    }
    printf("%d
", ans);

    return 0;
}
原文地址:https://www.cnblogs.com/miaomiao1220/p/6642333.html