题目链接:病毒[POI2000]
我们假设已经有一个无限长的串满足要求,那如果我们拿它去匹配会发生什么?
它会一直在AC自动机上转圈,一定经过根节点且不会经过病毒字符串结束的节点。
所以如果我们能找到一个环满足“一定经过根节点且不会经过病毒字符串结束的节点”,那么就可以找到一个无限长的串。
我们可以用dfs找环。
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <vector> using namespace std; int trie[30010][2], fail[30010], tot = 1; int n; bool End[30010], vis[30010], mark[30010], ans; char s[30010]; queue<int> q; void solve(int x) { if (ans) return; if (mark[x]) { ans = 1; return; } if (vis[x] || End[x]) return; vis[x] = 1; mark[x] = 1; if (trie[x][0]) solve(trie[x][0]); if (trie[x][1]) solve(trie[x][1]); mark[x] = 0; } int main() { cin >> n; for (int i = 1, p, len; i <= n; i++) { scanf("%s", s + 1); p = 1; len = strlen(s + 1); for (int j = 1; j <= len; j++) { int k = s[j] - '0'; if (!trie[p][k]) trie[p][k] = ++tot; p = trie[p][k]; } End[p] = 1; } for (int i = 0; i < 2; i++) trie[0][i] = 1; fail[1] = 0; q.push(1); while (!q.empty()) { int x = q.front(); q.pop(); for (int i = 0; i < 2; i++) { if (!trie[x][i]) { trie[x][i] = trie[fail[x]][i]; } else { fail[trie[x][i]] = trie[fail[x]][i]; End[trie[x][i]] |= End[fail[trie[x][i]]]; q.push(trie[x][i]); } } } solve(1); if (ans) puts("TAK"); else puts("NIE"); return 0; }