1. 程式人生 > >SPOJ1812 LCS2

SPOJ1812 LCS2

SPOJ1812 LCS2


題意:給n個串,求最長公共子串

做法:對第一個串建\(SAM\),拿剩餘的串類似於求\(LCS\)的在上面跑,對於當前這個串,求出可以到達每個狀態的最長子串長度,然後,每個狀態對每個串的匹配取最小值,最後取最大值就是答案。現在考慮如何求到達每個狀態的最長子串長度,我們先類似於求\(LCS\)的,維護一個\(now\)表示當前狀態,\(l\)表示匹配的長度,在跑的過程中更新每個狀態的最長子串長度,顯然更新完一個狀態後,這個狀態的所有有綴,即\(parent\)樹上,這個狀態的祖先們,都應該更新,於是在匹配都結束後,倒著拓撲序更新完所有的狀態。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>

const int N = 100010;
typedef long long ll;

using namespace std;

struct SAM {
    int n, step[N<<1], fa[N<<1], ch[N<<1][26], tmp[N<<1], num[N<<1], mn[N<<1], last, root, cnt, A[N];
    char s[N];
    void init() {
        memset(mn, 0x3f, sizeof(mn));
        cnt = 0; last = root = ++ cnt;
    }

    void add(int x) {
        int p = last, np = ++cnt;
        step[np] = step[p] + 1;
        while(p && !ch[p][x]) ch[p][x] = np, p = fa[p];

        if(!p) fa[np] = root;
        else {
            int q = ch[p][x];
            if(step[q] == step[p] + 1) fa[np] = q;
            else {
                int nq = ++ cnt;
                fa[nq] = fa[q]; memcpy(ch[nq], ch[q], sizeof(ch[q]));
                fa[q] = fa[np] = nq;  step[nq] = step[p] + 1;
                while(p && ch[p][x] == q) ch[p][x] = nq, p = fa[p];
            }
        }
        last = np;
    }
    void calright() {
        for(int i = 1; i <= cnt; ++i) ++ A[step[i]];
        for(int i = 1; i <= n; ++i) A[i] += A[i-1];
        for(int i = cnt; i; --i) num[A[step[i]]--] = i;
    }
    void run() {
        scanf(" %s",s+1), n = strlen(s + 1);
        for(int i = 1; i <= n; ++i) add(s[i]-'a');
        calright();
        memset(mn, 0x3f, sizeof(mn));
    }

    void solve(char b[]) {
        memset(tmp,0,sizeof(tmp));
        int m = strlen(b+1), now = 1, l = 0;
        for(int i = 1; i <= m; ++i) {
            if(ch[now][b[i] - 'a'])  ++ l, now = ch[now][b[i] - 'a'];
            else {
                while(now  && !ch[now][b[i] - 'a']) now = fa[now];
                if(!now) now = 1, l = 0;
                else l = step[now]+1, now = ch[now][b[i] - 'a'];
            }
            tmp[now] = max(tmp[now], l); /// only update the end
        }
        for(int i = cnt; i; --i) {
            mn[num[i]] = min(mn[num[i]], tmp[num[i]]);
            if( fa[num[i]] && tmp[num[i]] ) tmp[fa[num[i]]] = step[fa[num[i]]];
        }
    }

} Fe;

char str[N];

int main() {
    // freopen("in","r",stdin);
    Fe.init();
    Fe.run();
    while(~ scanf(" %s",str+1)) {
        Fe.solve(str);
    }
    int ans = 0;
    for(int i = 1; i <= Fe.cnt; ++i) ans = max(ans, Fe.mn[i]);
    printf("%d\n",ans);
    return 0;
}