题目链接
题目解法
看到有多串匹配,很大概率是
A
C
AC
AC 自动机
先把
A
C
AC
AC 自动机用
T
r
i
e
Trie
Trie 图建出来
令
e
d
[
u
]
(
0
/
1
)
ed[u](0/1)
ed[u](0/1) 表示
T
r
i
e
Trie
Trie 图上的
u
u
u 节点是否存在前缀与后缀相同,且前缀是一个病毒代码段的全部,虽然描述起来比较烦,但做过基础题的话
e
d
ed
ed 数组就很好理解了
如果字符串是有限的话,只要记录当前串与模板串的最长
b
o
r
d
e
r
border
border 的尾结点,然后不能经过
e
d
ed
ed 为
1
1
1 的点就可以了
拓展到无限长的话,只要能跳的点可以形成一个环就是
T
A
K
TAK
TAK,否则就是
N
I
E
NIE
NIE
找环的话用
d
f
s
dfs
dfs 就可以了
#include <bits/stdc++.h>
using namespace std;
const int N(30100);
int n;
char str[N];
int idx,tr[N][2],ne[N],ed[N];
bool vis[N];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
void insert(){
int len=strlen(str),p=0;
for(int i=0;i<len;i++){
int c=str[i]-'0';
if(!tr[p][c]) tr[p][c]=++idx;
p=tr[p][c];
}
ed[p]=1;
}
void build(){
int hh=0,tt=-1,que[N];
if(tr[0][0]) que[++tt]=tr[0][0];
if(tr[0][1]) que[++tt]=tr[0][1];
while(hh<=tt){
int u=que[hh++];
for(int i=0;i<2;i++){
int v=tr[u][i];
if(!v) tr[u][i]=tr[ne[u]][i];
else ne[v]=tr[ne[u]][i],ed[v]|=ed[tr[ne[u]][i]],que[++tt]=v;
}
}
}
void dfs(int u){
vis[u]=1;
for(int i=0;i<2;i++){
int v=tr[u][i];
if(ed[v]) continue;
if(vis[v]){
puts("TAK");
exit(0);
}
dfs(v);
}
vis[u]=0;
}
int main(){
n=read();
for(int i=1;i<=n;i++)
scanf("%s",str),insert();
build();
dfs(0);
puts("NIE");
return 0;
}