SPOJ1812 LCS2 - Longest Common Substring II【SAM LCS】

LCS2 - Longest Common Substring II

多个字符串找最长公共子串
以其中一个串建 \(SAM\),然后用其他串一个个去匹配,每次的匹配方式和两个串找 \(LCS\)一样,就是要记录 \(SAM\)的每个状态和当前匹配串匹配的最大值 \(maxx\),这个在匹配完一个串之后需要通过 \(parent\)树上传最大匹配值,同时要更新一个最小值 \(minn\),来表示每个节点和当前已经匹配过的所有串能匹配上的最大值,这个需要每次匹配一个串之后和当前节点的 \(maxx\)\(min\)

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2e5+7;
struct SAM{
    int len[MAXN],link[MAXN],ch[MAXN][26],tot,last,minn[MAXN],maxx[MAXN],c[MAXN],sa[MAXN];
    SAM(){ link[0] = -1; }
    void extend(int c){
        int np = ++tot, p = last;
        minn[np] = MAXN;
        len[np] = len[p] + 1;
        while(p!=-1 and !ch[p][c]){
            ch[p][c] = np;
            p = link[p];
        }
        if(p==-1) link[np] = 0;
        else{
            int q = ch[p][c];
            if(len[p]+1==len[q]) link[np] = q;
            else{
                int clone = ++tot;
                minn[clone] = MAXN;
                link[clone] = link[q];
                len[clone] = len[p] + 1;
                memcpy(ch[clone],ch[q],sizeof(ch[q]));
                link[np] = link[q] = clone;
                while(p!=-1 and ch[p][c]==q){
                    ch[p][c] = clone;
                    p = link[p];
                }
            }
        }
        last = np;
    }
    void Radix_sort(){
        for(int i = 1; i <= tot; i++) c[i] = 0;
        for(int i = 0; i <= tot; i++) c[len[i]]++;
        for(int i = 1; i <= tot; i++) c[i] += c[i-1];
        for(int i = tot; i >= 0; i--) sa[c[len[i]]--] = i;
    }
    void match(char *s){
        int u = 0, ls = 0;
        for(int i = 0, l = strlen(s); i < l; i++){
            int c = s[i] - 'a';
            while(u and !ch[u][c]) u = link[u], ls = len[u];
            if(ch[u][c]) u = ch[u][c], ls++;
            maxx[u] = max(maxx[u],ls);
        }
        for(int i = tot + 1; i >= 1 and sa[i]; i--){
            int u = sa[i];
            minn[u] = min(minn[u],maxx[u]);
            maxx[link[u]] = max(maxx[link[u]],min(len[link[u]],maxx[u]));
            maxx[u] = 0;
        }
    }
    int LCS(){ int ret = 0; for(int i = 0; i <= tot; i++) ret = max(ret,minn[i]); return ret; }
}sam;
char s[MAXN];
int main(){
    scanf("%s",s);
    for(int i = 0, l = strlen(s); i < l; i++) sam.extend(s[i]-'a');
    sam.Radix_sort();
    while(scanf("%s",s)!=EOF) sam.match(s);
    printf("%d\n",sam.LCS());
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/kikokiko/p/12704280.html