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