bzoj 2938: [Poi2000]病毒

安在信息安全新媒体 2017-12-23

2938: [Poi2000]病毒

Time Limit:1 SecMemory Limit:128 MB
Submit: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 ;
}

相关推荐