BZOJ2938 [Poi2000]病毒
Description
- 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。
如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。
现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
示例:例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。
如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。
任务:请写一个程序:l 读入病毒代码;l 判断是否存在一个无限长的安全代码;l 将结果输出
- 第一行包括一个整数n,表示病毒代码段的数目。
以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。
所有病毒代码段的总长度不超过30000。
Output
- 第一行输出一个单词:
TAK——假如存在这样的代码;
NIE——如果不存在。
- 3
01
11
00000
Sample Output 1
- NIE
Source
- [Poi2000]
思路
- AC自动机模板题,将病毒串建AC自动机
- 可以发现当AC自动机上满足如下条件时有无限长的安全代码输出 TAK
- 有环
- 环不经过病毒串的结尾字符
- 也必须不经过病毒串的结尾字符所在的 (fail) 链上的所有字符
- 否则输出 NIE
code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=2;
const int Max=30010;
int n;
char s[Max];
struct Trie
{
int nx[Max][N],fail[Max];
bool vis[Max],end[Max],ins[Max];
int root,tot;
int newnode()
{
for(int i=0; i<N; i++) nx[tot][i]=-1;
end[tot++]=false;
return tot-1;
}
void init(){ tot=0,root=newnode(); }
void insert(char s[])
{
int len=strlen(s),now=root,k;
for(int i=0; i<len; i++)
{
k=(int)(s[i]-'0');
if(nx[now][k]==-1) nx[now][k]=newnode();
now=nx[now][k];
}
end[now]=true;
}
void build()
{
queue<int> Q;
fail[root]=root;
for(int i=0; i<N; i++)
if(nx[root][i]==-1) nx[root][i]=root;
else fail[nx[root][i]]=root,Q.push(nx[root][i]);
int now;
while(!Q.empty())
{
now=Q.front();Q.pop();
for(int i=0; i<N; i++)
if(nx[now][i]==-1) nx[now][i]=nx[fail[now]][i];
else
end[nx[now][i]]=end[nx[now][i]]|end[nx[fail[now]][i]],
//必须不经过病毒串的结尾字符所在的fail链上的所有字符
fail[nx[now][i]]=nx[fail[now]][i],
Q.push(nx[now][i]);
}
}
bool dfs(int t)
{
ins[t]=true;//标记访问路径
for(int i=0; i<N; i++)
{
if(ins[nx[t][i]]) return true;
if(end[nx[t][i]]||vis[nx[t][i]]) continue;
vis[nx[t][i]]=true;//标记该条路径是否走过
if(dfs(nx[t][i])) return true;//继续访问
}
ins[t]=false;
return 0;
}//判断是否有满足条件的环
void pd()
{
if(dfs(0)) cout<<"TAK"<<endl;
else cout<<"NIE"<<endl;
}
}ac;
int main()
{
ac.init();
scanf("%d",&n);
for(int i=0; i<n; i++)
scanf("%s",s),ac.insert(s);
ac.build();
ac.pd();
return 0;
}