传送门
题意:略
构建AC自动机,无限长的安全代码满足能一直在AC自动机上匹配但始终匹配不上任何一个危险串。从根往下dfs(只走不作为危险串结尾的结点),如果能找到一个环,就存在无限长的安全代码,否则不存在。找环用拓扑排序实现。
注意:所有字符串的题,siz,cnt等变量一定千万切记不要错写成char,否则可能会在废掉五六个小时orz。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=3e4+5;
int n;
char s[maxn];
int head[maxn],edge=0,ind[maxn],siz=0;
struct EDGE {
int v,nxt;
}e[maxn<<1];
inline void adde(int u,int v) {
e[edge].nxt=head[u],e[edge].v=v,head[u]=edge++;
}
struct AC_automation {
int ch[maxn][2],fail[maxn];
bool vis[maxn],end[maxn];
inline void init() {
memset(ch,0,sizeof(ch)),
memset(vis,false,sizeof(vis)),
memset(end,false,sizeof(end));
}
inline void insert(char *s) {
int len=strlen(s),now=0;
for (int i=0;i<len;++i) {
int x=s[i]-'0';
if (!ch[now][x]) ch[now][x]=++siz;
now=ch[now][x];
}
end[now]=1;
}
inline void build() {
queue<int> q;
while (!q.empty()) q.pop();
if (ch[0][0]) q.push(ch[0][0]);
if (ch[0][1]) q.push(ch[0][1]);
while (!q.empty()) {
int now=q.front();q.pop();
for (int i=0;i<=1;++i) {
if (!ch[now][i]) {ch[now][i]=ch[fail[now]][i];continue;}
fail[ch[now][i]]=ch[fail[now]][i];
if (end[fail[ch[now][i]]]) end[ch[now][i]]=1;
q.push(ch[now][i]);
}
}
}
void dfs(int p) {
vis[p]=true;
for (int i=0;i<=1;++i) {
adde(p,ch[p][i]),++ind[ch[p][i]];
if (!vis[ch[p][i]]&&!end[ch[p][i]]) dfs(ch[p][i]);
}
}
}AC;
inline bool Topo() {
queue<int> q;
int tim=0;
while (!q.empty()) q.pop();
for (int i=0;i<=siz;++i)
if (!ind[i]) q.push(i);
while (!q.empty()) {
int p=q.front();q.pop();
++tim;
for (int i=head[p];~i;i=e[i].nxt) {
int v=e[i].v;
--ind[v];
if (!ind[v]) q.push(v);
}
}
return tim==siz+1;//found circle->true->NIE
//why +1:0(root) is a node as well
}
int main() {
// freopen("bzoj 2938.in","r",stdin);
AC.init();
memset(head,-1,sizeof(head));
memset(ind,0,sizeof(ind));
scanf("%d",&n);
while (n--) {
scanf("%s",s);
AC.insert(s);
}
AC.build();
AC.dfs(0);
puts(Topo()?"NIE":"TAK");
return 0;
}