题意:
给定n个病毒串,只由0和1组成,
问是否存在某种无限长的串,不包含任何病毒子串。
数据范围:n<=2e3,病毒串的总长不超过3e4
解法:
对匹配串建立ac自动机,
题目需要不包含匹配串的无限长串,
那么就是可以在ac自动机上无限走,
在ac自动机上dfs找不包含标记点的环即可.
ac自动机的trie图是有向图,
所以要用有向图找环算法(不是无向图).
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=2e6+5;
char s[maxm];
int n;
struct AC{
int a[maxm][2],fail[maxm],val[maxm],tot=0;
void init(){//清空
for(int i=0;i<=tot;i++){
memset(a[i],0,sizeof a[i]);
val[i]=fail[i]=0;
}
tot=0;
}
void add(char *s){//建立trie树
int len=strlen(s);
int node=0;
for(int i=0;i<len;i++){
int v=s[i]-'0';
if(!a[node][v])a[node][v]=++tot;
node=a[node][v];
}
val[node]=1;//标记结尾
}
void build(){//构造fail
queue<int>q;
for(int i=0;i<2;i++){
if(a[0][i]){
q.push(a[0][i]);
}
}
while(!q.empty()){
int x=q.front();
q.pop();
val[x]|=val[fail[x]];
for(int i=0;i<2;i++){
if(a[x][i]){
fail[a[x][i]]=a[fail[x]][i];
q.push(a[x][i]);
}else{
a[x][i]=a[fail[x]][i];
}
}
}
}
int mark[maxm];
int cir=0;
void dfs(int x){
if(cir)return ;
mark[x]=1;
for(int i=0;i<2;i++){
int v=a[x][i];
if(val[v])continue;
if(!mark[v]){
dfs(v);
}else{
cir=1;return ;
}
}
mark[x]=0;
}
void solve(){
dfs(0);
}
}ac;
signed main(){
ac.init();
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s);
ac.add(s);
}
ac.build();
ac.solve();
if(ac.cir){
puts("TAK");
}else{
puts("NIE");
}
return 0;
}