bzoj 2938 [Poi2000]病毒 AC自动机

题面

题目传送门

解法

AC自动机……尼玛我就是一个自动WA题机……

  • 有多串匹配,所以我们可以对这 n 个0/1串建出一个AC自动机
  • 然后我们可以发现,在我们建出的这一个Trie图上,如果存在一个无限长的0/1串,那么一定可以在这张图上跑并且一直在环上绕
  • 那么,问题就转化成给定一个起点,问是否存在环
  • 显然dfs就可以了
  • 时间复杂度: O ( | s i | )

【注意事项】
- 因为AC自动机上 f a i l 指针对应的是当前这个串的最长后缀,如果这个后缀是病毒的话,那么这个串也一定是病毒
- dfs的时候注意复杂度问题

代码

#include <bits/stdc++.h>
#define N 30010
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
    x = 0; int f = 1; char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
    while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
struct AC_Automaton {
    struct Node {
        int fail, cnt, child[2];
    } t[N];
    int tot, f[N], vis[N];
    void ins(char *st) {
        int l = strlen(st), now = 0;
        for (int i = 0; i < l; i++) {
            int x = st[i] - '0';
            if (!t[now].child[x]) t[now].child[x] = ++tot;
            now = t[now].child[x];
        }
        t[now].cnt = 1;
    }
    void build() {
        queue <int> q;
        for (int i = 0; i <= 1; i++)
            if (t[0].child[i]) q.push(t[0].child[i]);
        while (!q.empty()) {
            int x = q.front(); q.pop();
            for (int i = 0; i <= 1; i++)
                if (t[x].child[i]) {
                    int y = t[x].child[i];
                    t[y].fail = t[t[x].fail].child[i];
                    t[y].cnt |= t[t[y].fail].cnt;
                    q.push(y);
                } else t[x].child[i] = t[t[x].fail].child[i];
        }
    }
    void dfs(int x) {
        vis[x] = 1;
        for (int i = 0; i <= 1; i++) {
            int y = t[x].child[i];
            if (vis[y]) {cout << "TAK\n"; exit(0);}
            if (!t[y].cnt && !f[y]) f[y] = 1, dfs(y);
        }
        vis[x] = 0;
    }
    void solve() {
        dfs(0);
        cout << "NIE\n";
    }
} AC;
char st[N];
int main() {
    int n; read(n);
    for (int i = 1; i <= n; i++) {
        scanf(" %s", st);
        AC.ins(st);
    }
    AC.build(); AC.solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/emmmmmmmmm/article/details/82118620