2020 CCPC Wannafly冬のキャンプ2日目D. Karabash文字列(サフィックスオートマトン)

トピックます。https://ac.nowcoder.com/acm/contest/4010

(ひょうたん主のNB!)

それはまだ非常に疑問を混乱だ、シーンは、ゲームが問題を発見した後、最終的な交流では2つだけのチームが、私は...サムが10分以内の数行を変更するためにボードのコピーを裸このトピックを開くには行かなかったです。

重要事前知識:二つのノード上のSAMは、親木のLCAをLCP文字列を表します。

実際には、ここにこの質問は(すなわち、息子を持っている)、そしてあなたは、主題のコレクションの要件にそれを置く明らかMEX操作し、値を探し出すことができます(質問は裸のものですので!)、長いノードのSAM LCAなどとして行わ文字列とOの暴力、複雑さ(N)のように求めて継続する要求アウトに基づいて、その後、成長を非減少するたびに値をとります。

注ツリーの平均親ノードのために、限り、彼は息子を持っていたとして、彼は資格のLCA(彼自身と彼の息子のLCA彼自身が)ですが、ルートノードが同じではない、ということ、を意味するものではありませんので、サフィックスのルートノード、それは、彼がLCA自身と別のノードになることはできませんが、それは、LCA他の2つのノード(で、2度以上の統計的長さLCPに0友人の唯一のルート)になることができ、ここでは、特別な文を必要としています。

PPTソリューションのボンボンと同様に2だけでなく、非常に多くの同じ、2つのサフィックスがLCPを存在する場合、我々は削除されている最初の2文字の接尾辞を入れて、我々は、彼らはまだ、LCP存在していることがわかります、長さが前に削除され-1限り、あなたは接尾語長LCP xがあります見つけると、それから1からLCPの長さX長さに存在しているので、他の言葉で、それは価値のMEXの暴力を維持することはできません、それはLCAとしてだけですべてする必要があります最大の長さを取る、それから1ポイント表現は答えがあります。

具体的な実践では、唯一の文字を追加しながら、親木は、建設SAM時のメンテナンスなどの局所的な変更操作を有しています。

ACコード:

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e6 + 5;

int _;
char s[maxn];

struct Sam {
    int next[maxn << 1][26];
    int link[maxn << 1], step[maxn << 1];
    int rcnt;
    unordered_set<int> vis;
    int sz, last, root;

    void init() {
        root = sz = last = 1;
        vis.clear();
        rcnt = 0;
        memset(next[root], 0, sizeof(next[root]));
    }

    void add(int c) {
        int p = last;
        int np = ++sz;
        last = np;


        memset(next[np], 0, sizeof(next[np]));
        step[np] = step[p] + 1;
        while (!next[p][c] && p) {
            next[p][c] = np;
            p = link[p];
        }

        if (p == 0) {
            link[np] = root;
            if (++rcnt > 1) {
                vis.insert(0);
                rcnt = INT_MIN;
            }
        } else {
            int q = next[p][c];
            if (step[p] + 1 == step[q]) {
                link[np] = q;
                if (!vis.count(step[q])) {
                    vis.insert(step[q]);
                }
            } else {
                int nq = ++sz;
                memcpy(next[nq], next[q], sizeof(next[q]));
                step[nq] = step[p] + 1;
                link[nq] = link[q];
                link[q] = link[np] = nq;
                if(!vis.count(step[nq])){
                    vis.insert(step[nq]);
                }
                while (next[p][c] == q && p) {
                    next[p][c] = nq;
                    p = link[p];
                }
            }
        }
    }

    void solve() {
        init();

        int g = 0;
        for (int i = 0, len = strlen(s); i < len; i++) {
            add(s[i] - 'a');

            while (vis.count(g)) {
                ++g;
            }
            printf("%d%c", g, i < len - 1 ? ' ' : '\n');
        }
    }
} sam;

int main() {
    scanf("%d", &_);
    while (_--) {
        scanf("%s", s);
        sam.solve();
    }
    return 0;
}
公開された156元の記事 ウォン称賛20 ビュー60000 +

おすすめ

転載: blog.csdn.net/Cymbals/article/details/104057431