Description
二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
示例: 例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11,
000000}为病毒代码段,那么就不存在一个无限长的安全代码。 任务: 请写一个程序: l 读入病毒代码; l
判断是否存在一个无限长的安全代码; l 将结果输出
Input
第一行包括一个整数n,表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。
Output
你应在在文本文件WIN.OUT的第一行输出一个单词: l TAK——假如存在这样的代码; l
NIE——如果不存在。
Sample Input
3
01
11
00000
Sample Output
NIE
题解
建出AC机
先把病毒传递一下…
在AC机上跑
我们的目标是两次合法跑到同一个状态,因为这样就可以无限循环了嘛…
那就大力跑啊…
不加传递会凉凉
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void write(int x)
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
}
inline void print(int x){write(x);printf(" ");}
struct node{int son[2],s,fail;}tr[31000];int root,trlen;
char ch[31000];
void add()
{
int len=strlen(ch+1),p=root;
for(int i=1;i<=len;i++)
{
int y=ch[i]-'0';
if(!tr[p].son[y])tr[p].son[y]=++trlen;
p=tr[p].son[y];
}
tr[p].s++;
}
queue<int> q;
void build_fail()
{
q.push(0);
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=0;i<=1;i++)
{
int y=tr[x].son[i];
if(!y)continue;
if(x==0)tr[y].fail=0;
else
{
int j=tr[x].fail;
while(j&&!tr[j].son[i])j=tr[j].fail;
j=tr[j].son[i];tr[y].fail=j;
}
q.push(y);
}
if(tr[tr[x].fail].s)tr[x].s=1;
}
}
bool v[31000],hh[31000];
bool ok(int x)
{
if(tr[x].s)return false;
if(v[x])return true;
v[x]=true;
for(int i=0;i<=1;i++)
{
int y=x;
while(y&&!tr[y].son[i])y=tr[y].fail;
y=tr[y].son[i];
if(v[y])return true;
if(hh[y])continue;hh[y]=1;
if(ok(y))return true;
}
v[x]=false;
return false;
}
int n;
int main()
{
n=read();
for(int i=1;i<=n;i++)scanf("%s",ch+1),add();
build_fail();
if(ok(0))puts("TAK");
else puts("NIE");
return 0;
}