P2444 [POI2000]病毒

链接

洛谷P2444(数据很水)
LOJ#10062

题解

这题问我们能否构造一个无限长的串使得所有模式串均无法匹配,也就是说这个长串会在AC自动机上绕来绕去,不经过任何一个模式串的结尾。所以在trie图中有两类结点不能经过:表示单词结尾的结点和fail指针指向单词结尾的结点。如果剩下的trie边和转移边能形成环,才能构造出题目要求的串。

然后就变成了一个图论问题,用DFS找环。洛谷的数据很水,错误复杂度的DFS也能过。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 9;
struct tnode
{
    int ch[2];
    int cnt, fail;
};
tnode trie[maxn];
int tot, n;
bool flag[maxn], vis[maxn], used[maxn];
void ins(string &s)
{
    int len = s.length(), now = 0;
    for (int i = 0; i < len; ++i)
    {
        int c = s[i] - '0';
        if (!trie[now].ch[c])
            trie[now].ch[c] = ++tot;
        now = trie[now].ch[c];
    }
    flag[now] = 1;
}
void build()
{
    queue<int> q;
    if (trie[0].ch[0])
        q.push(trie[0].ch[0]);
    if (trie[0].ch[1])
        q.push(trie[0].ch[1]);
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (int i = 0; i < 2; ++i)
        {
            int &now = trie[u].ch[i];
            if (now)
            {
                trie[now].fail = trie[trie[u].fail].ch[i];
                flag[now] |= flag[trie[now].fail];
                q.push(now);
            }
            else
            {
                now = trie[trie[u].fail].ch[i];
            }
        }
    }
}
bool dfs(int now)
{
    vis[now] = 1;
    for (int i = 0; i < 2; ++i)
    {
        int &to = trie[now].ch[i];
        if (vis[to])
            return 1;
        if (flag[to] || used[to])
            continue;
        used[to] = 1;
        if (dfs(to))
            return 1;
    }
    vis[now] = 0;
    return 0;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n;
    string s;
    for (int i = 1; i <= n; ++i)
    {
        cin >> s;
        ins(s);
    }
    build();
    cout << (dfs(0) ? "TAK" : "NIE") << endl;
    return 0;
}
上一篇:Trie


下一篇:leetcode 421.数组中两个数的最大异或值 - 字典树 + 贪心