题面
解法
AC自动机……尼玛我就是一个自动WA题机……
- 有多串匹配,所以我们可以对这 个0/1串建出一个AC自动机
- 然后我们可以发现,在我们建出的这一个Trie图上,如果存在一个无限长的0/1串,那么一定可以在这张图上跑并且一直在环上绕
- 那么,问题就转化成给定一个起点,问是否存在环
- 显然dfs就可以了
- 时间复杂度:
【注意事项】
- 因为AC自动机上
指针对应的是当前这个串的最长后缀,如果这个后缀是病毒的话,那么这个串也一定是病毒
- 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;
}