bzoj 2938: [Poi2000]病毒
2938: [Poi2000]病毒
Time Limit:1 SecMemory Limit:128 MBSubmit:1111Solved:556
[Submit][Status][Discuss]
Description
二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
示例:
例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。
任务:
请写一个程序:
l读入病毒代码;
l判断是否存在一个无限长的安全代码;
l将结果输出
Input
第一行包括一个整数n,表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。
Output
你应在在文本文件WIN.OUT的第一行输出一个单词:
lTAK——假如存在这样的代码;
lNIE——如果不存在。
Sample Input
3
01
11
00000
Sample Output
NIE
/*
建立AC自动机,在不能走每个单词最后一个字母的前提下,如果某个字符串在自动机上无法匹配,
则说明可以找到无限长的字符串。
为了方便起见,将所有的fail指针合并,最后在自动机上搜索就行了。
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define maxn 30010
int n,sz=,a[maxn][],fail[maxn],word[maxn];
bool ins[maxn],vis[maxn];
char s[maxn];
void insert(){
int now=,len=strlen(s);
for(int i=;i<len;i++){
int t=s[i]-'';
if(!a[now][t])a[now][t]=++sz;
now=a[now][t];
}
word[now]=;
}
void acmach(){
queue<int>q;
q.push();fail[]=;
while(!q.empty()){
int now=q.front();q.pop();
for(int i=;i<;i++){
if(!a[now][i]){a[now][i]=a[fail[now]][i];continue;}
int k=fail[now];
while(!a[k][i])k=fail[k];
fail[a[now][i]]=a[k][i];
word[a[now][i]]|=word[a[k][i]];
q.push(a[now][i]);
}
}
}
bool dfs(int x){
ins[x]=;
for(int i=;i<;i++){
if(ins[a[x][i]])return ;
if(vis[a[x][i]]||word[a[x][i]])continue;
vis[a[x][i]]=;
if(dfs(a[x][i]))return ;
}
ins[x]=;
return ;
}
int main(){
for(int i=;i<;i++)a[][i]=;
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%s",s);
insert();
}
acmach();
if(dfs())printf("TAK");
else printf("NIE");
return ;
} 相关推荐
Watanuki00 2020-01-31
原始饮食 2018-04-21
BitTigerio 2018-03-10
迷思 2018-02-09
真匿名打脸爱好者 2018-02-07
迷思 2018-01-11
那些年那些有趣的数学 2018-01-05
心理学哲学批判性思维 2017-12-27
BitTigerio 2017-12-24
明学的白板 2017-12-16