P2444 [POI2000]病毒
P2444 [POI2000]病毒
题意:给01模板串,判断是否存在无限长01串不包含任何一个模板串
一眼看过去没头绪,还以为挺难
一看是蓝题,
那我就画画图吧
画了只AC自动机
然后就发现只要dfs且怎么走都会碰到end时就不存在安全代码
那就找环呗,只要这个环上没有病毒的结尾就可以一直循环
开始想的是把所有end及其相关边去掉看看有没有环
但题目只求存在性
那就dfs重复到达一个节点就退出来嘛
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int N=5000000+5;
template<class T>inline void read(T &num){
char ch;
while(!isdigit(ch=getchar()));
num=ch-'0';
while(isdigit(ch=getchar()))num=num*10+ch-'0';
}
int tri[N][2],is_end[N],fail[N],vis[N],totn,n;
inline void Insert(char s[]){
int len=strlen(s),x=0;
for(int p=0;p<len;++p){
int ch=s[p]-'0';
if(tri[x][ch]==0)tri[x][ch]=++totn;
x=tri[x][ch];
}
is_end[x]=1;
}
queue<int> que;
inline void Fail(){
int x=0;
if(tri[x][0])que.push(tri[x][0]);
if(tri[x][1])que.push(tri[x][1]);
while(que.size()){
x=que.front();que.pop();
if(is_end[fail[x]])is_end[x]=1;
//printf("fail[%d]=%d\n",x,fail[x]);
if(tri[x][0])fail[tri[x][0]]=tri[fail[x]][0],que.push(tri[x][0]);
else tri[x][0]=tri[fail[x]][0];
if(tri[x][1])fail[tri[x][1]]=tri[fail[x]][1],que.push(tri[x][1]);
else tri[x][1]=tri[fail[x]][1];
}
}
bool dfs(int x=0){
//printf("vis[%d]=%d\n",x,vis[x]);
if(vis[x])return true;
vis[x]=1;
//printf("tri[x]=(%d,%d)\n",tri[x][0],tri[x][1]);
//printf("is_end(%d,%d)\n",is_end[tri[x][0]],is_end[tri[x][1]]);
if(!is_end[tri[x][0]])if(dfs(tri[x][0]))return true;
if(!is_end[tri[x][1]])if(dfs(tri[x][1]))return true;
vis[x]=0;
return false;
}
char s[30000+5];
int main(){
read(n);
for(int i=1;i<=n;++i){
scanf("%s",s);
Insert(s);
}
Fail();
printf("%s",dfs()?"TAK":"NIE");
return 0;
}