[SPOJ1812-LCS2]Longest Common Substring II

壹、题目描述 ¶

传送门 to Vjudge.

贰、题解 ¶

曾经研究过这个问题,然而记不起来了......今天对着一个点想了很久。

为什么每次匹配一个字符串的时候要用一个 tmp[] 存下最大值而不能直接更新 mn[] ?因为匹配一个串的时候,在某些情况下我们不可避免地会走到同一个点,这个时候就应该从两次中取较大的一次。

另,每次匹配完之后需要更新父亲,因为儿子(更长的)都能被匹配到,那么父亲为什么不能被匹配呢?

不能在最后上传,留作思考。

叁、参考代码 ¶

const int maxn=200000; // twice
const int sigma=26;
const int inf=0x3f3f3f3f;

int trie[maxn+5][sigma], fa[maxn+5];
int len[maxn+5], mn[maxn+5], tmp[maxn+5];
int ncnt=1, lst=1;
inline void add(int c){
    int p=lst, u=lst=++ncnt;
    len[u]=len[p]+1;
    for(; p && !trie[p][c]; p=fa[p])
        trie[p][c]=u;
    if(!p) fa[u]=1;
    else{
        int q=trie[p][c];
        if(len[q]==len[p]+1) fa[u]=q;
        else{
            int nq=++ncnt;
            mmcpy(trie[nq], trie[q]);
            fa[nq]=fa[q], len[nq]=len[p]+1;
            fa[q]=fa[u]=nq;
            for(; p && trie[p][c]==q; p=fa[p])
                trie[p][c]=nq;
        }
    }
}

char s[maxn+5];
int n;

vector<int>g[maxn+5];
inline void buildTre(){
    rep(i, 2, ncnt) g[fa[i]].push_back(i);
}
/** @brief update @p mn[] */
void dfs(int u){
    for(int v: g[u])
        dfs(v), mn[u]=max(mn[u], mn[v]);
}

inline void buildSAM(){
    rep(i, 1, n) add(s[i]-'a');
    rep(i, 1, ncnt) mn[i]=inf;
    buildTre();
}

inline void compare(){
    int u=1, cur_len=0;
    rep(i, 0, ncnt) tmp[i]=0;
    rep(i, 1, n){
        int to=s[i]-'a';
        while(u && !trie[u][to])
            u=fa[u], cur_len=min(cur_len, len[u]);
        if(!u) u=1, cur_len=0;
        else u=trie[u][to], ++cur_len;
        tmp[u]=max(tmp[u], cur_len);
    }
    rep(i, 2, ncnt)
        mn[i]=min(mn[i], tmp[i]);
    dfs(1); // update @p mn[]
}

signed main(){
    int fir=1;
    while(~scanf("%s", s+1)){
        n=strlen(s+1);
        if(fir) buildSAM(), fir=0;
        else compare();
    }
    // dfs(1);
    int ans=0;
    rep(i, 2, ncnt) if(mn[i]<inf)
        ans=max(ans, mn[i]);
    writc(ans);
    return 0;
}
posted @ 2021-08-18 22:49  Arextre  阅读(23)  评论(0编辑  收藏  举报