SPOJ - LCS2 (后缀自动机)

题意

给若干个串,求这些串最长公共子串的长度。

传送门

思路

后缀自动机求lcs模版题。

Code

#include 

using namespace std;

const int maxn = 2e5+10;

struct Pam {
    int len[maxn], link[maxn];
    int nxt[maxn][26];
    int last, tot;
    int mx[maxn], mi[maxn];

    void init() {
        len[0] = link[0] = 0;
        last = tot = 1;
    }

    void extend(int c) {
        c -= 'a';
        int cur = ++tot, p = last;
        len[cur] = len[last] + 1;
        for (; p && !nxt[p][c]; p = link[p]) nxt[p][c] = cur;
        if(!p) {
            link[cur] = 1;
        } else {
            int q = nxt[p][c];
            if(len[q] == len[p]+1) {
                link[cur] = q;
            } else {
                int clone = ++tot;
                len[clone] = len[p] + 1;
                memcpy(nxt[clone], nxt[q], sizeof(nxt[q]));
                link[clone] = link[q];
                for (; p && nxt[p][c] == q; p = link[p]) nxt[p][c] = clone;
                link[q] = link[cur] = clone;
            }
        }
        last = cur;
    }

    int c[maxn], a[maxn];

    void topo(int n) {
        for (int i = 1; i <= tot; ++i) c[i] = 0;
        for (int i = 1; i <= tot; ++i) ++c[len[i]];
        for (int i = 1; i <= tot; ++i) c[i] += c[i-1];
        for (int i = 1; i <= tot; ++i) a[c[len[i]]--] = i;
        for (int i = 1; i <= tot; ++i) mi[i] = len[i];
    }

    void solve(const string &s) {
        int p = 1, cnt = 0, ans = 0;
        for (int i = 1; i <= tot; ++i) mx[i] = 0;
        for (int i = 0; s[i]; ++i) {
            int c = s[i] - 'a';
            if(nxt[p][c]) {
                ++cnt;
                p = nxt[p][c];
            } else {
                for (; p && !nxt[p][c]; p = link[p]);
                if(!p) cnt = 0, p = 1;
                else cnt = len[p]+1, p = nxt[p][c];
            }
            mx[p] = max(mx[p], cnt);
        }
        for (int i = tot; i >= 1; --i) mx[link[a[i]]] = max(mx[link[a[i]]], mx[a[i]]);
        for (int i = 1; i <= tot; ++i) mi[i] = min(mi[i], mx[i]);
    }

    void write() {
        int ans = 0;
        for (int i = 1; i <= tot; ++i) ans = max(ans, mi[i]);
        printf("%d\n", ans);
    }
}sam;
string str;

int main() {
//    freopen("input.in", "r", stdin);
    sam.init();
    cin >> str;
    int n = str.length();
    for (int i = 0; str[i]; ++i) sam.extend(str[i]);
    sam.topo(n);
    while(cin >> str)
        sam.solve(str);
    sam.write();
    return 0;
}

你可能感兴趣的:(SPOJ - LCS2 (后缀自动机))