https://www.luogu.org/problem/P2444
分析
手玩样例可以发现一个无限长的安全串放到危险代码的AC自动机中匹配,一定会成环
将fail也视为一条单向边,DFS跑个不经过任何代码结尾的环即可
特殊的,如果一个点的fail指向一个代码的结尾,那么这个节点也是危险的(这个串的最长公共后缀是个危险代码)

#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <queue> using namespace std; const int N=3e4+10; int fail[N],c[N][2],f[N],cnt=0; bool vis[N],end[N],ok; string s; int n; void Insert(string s) { int len=s.length(),x=0; for (int i=0;i<len;i++) { if (!c[x][s[i]-48]) f[c[x][s[i]-48]=++cnt]=x; x=c[x][s[i]-48]; } end[x]=1; } void Build() { queue<int> q; while (!q.empty()) q.pop(); if (c[0][0]) q.push(c[0][0]); if (c[0][1]) q.push(c[0][1]); while (!q.empty()) { int u=q.front();q.pop(); end[u]|=end[fail[u]]; for (int i=0;i<2;i++) if (c[u][i]) { q.push(c[u][i]); fail[c[u][i]]=c[fail[u]][i]; } else c[u][i]=c[fail[u]][i]; } } void DFS(int u) { if (end[u]) return; if (vis[u]) { printf("TAK ");ok=1; return; } vis[u]=1; if (c[u][0]) DFS(c[u][0]); if (ok) return; if (c[u][1]) DFS(c[u][1]); if (ok) return; vis[u]=0; } int main() { scanf("%d",&n); for (int i=1;i<=n;i++) { cin>>s; Insert(s); } Build(); DFS(0); if (!ok) printf("NIE "); }