[ACオートマトン]玄武岩パスワード

タイトル説明

長さ\(N \)文字列の4つの要素が存在している:N、S、W、N 。

長さM列の100のパターンがあります。

今、各パターン文字列は最長プレフィックス文字列の長さと一致していることが必要です。

サンプル入力

7時03分
SNNSSNS
NNSS
NNN
WSEE

サンプル出力

4
2
0

問題の解決策

これは、AC自動機のテンプレートのテーマ

キーは、パターン文字列がプレフィックス一致しているかどうかを判断することです

接頭辞を表すノードACオートマトンがポインタマークが横断することができるので、すべての一致プレフィックスをフェイル

第1のパターン文字列がトライ、オートマトンの構成に挿入されます

その後、AC自動機への文字列の入力は、すなわち、接頭辞マッチしたノードが出てマークされています。特定のマークのルートにあるため、このノード、そこに現在のノードがマークされている場合剪定は、であり、それは破ることができます。

最後に、現在のノードが答えをマークされている場合、各モードとAC列オートマトンへのその後の入力は、更新されます。数字現在のノードが一致した接頭辞です。

コード

始まりがあります小さな詳細重要なことは、RE原因の注意を払っていません

400オープン配列、* 4 100次に根拠

それは本当に長い時間が理解できなかったため、引退確かに400以上の状態、四分木ノウハウを描いている、状態の数は、文字列のより適切な全体の長さを選択する必要があります

#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>

using namespace std;
const int N = 110;
const int M = 1e5 + 7;
namespace AC {
    int tr[10000000][4], tot;
    int fail[10000000];
    bool vis[10000000];


    inline int id(char ch) {
        if (ch == 'E') return 0;
        else if (ch == 'S') return 1;
        else if (ch == 'W') return 2;
        else if (ch == 'N') return 3;
        return 0;
    }

    void insert(char *s) {
        int u = 0, k = 0;
        for (int i = 1; s[i]; ++i) {
            k = id(s[i]);
            if (!tr[u][k]) tr[u][k] = ++tot;
            u = tr[u][k];
        }
    }

    queue<int> q;

    void build() {
        for (int i = 0; i < 4; ++i) {
            if (tr[0][i]) {
                q.push(tr[0][i]);
            }
        }
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = 0; i < 4; ++i) {
                if (tr[u][i]) {
                    fail[tr[u][i]] = tr[fail[u]][i];
                    q.push(tr[u][i]);
                } else {
                    tr[u][i] = tr[fail[u]][i];
                }
            }
        }
    }

    void query(char *t) {
        int u = 0;
        for (int i = 1; t[i]; ++i) {
            u = tr[u][id(t[i])];
            for (int j = u; j && vis[j] != 1; j = fail[j]) {
                vis[j] = true;
            }
        }
    }

    int get_ans(char *s) {
        int u = 0, res = 0;
        for (int i = 1; s[i]; ++i) {
            u = tr[u][id(s[i])];
            if (vis[u]) res = i;
        }
        return res;
    }
}
char str[M][N];
char p[10000005];

int main() {
    int n, m;
    scanf("%d %d", &n, &m);
    scanf("%s", p + 1);
    for (int i = 1; i <= m; ++i) {
        scanf("%s", str[i] + 1);
        AC::insert(str[i]);
    }
    AC::build();
    AC::query(p);
    for (int i = 1; i <= m; ++i) {
        printf("%d\n", AC::get_ans(str[i]));
    }
    return 0;
}

 問題はしかし前に行われますが、長い時間を忘れて、その本質の本当の理解がなかったです

おすすめ

転載: www.cnblogs.com/smallocean/p/12240680.html