1. 程式人生 > >bzoj 2938: [Poi2000]病毒

bzoj 2938: [Poi2000]病毒

empty 例如 post php for 整數 pty sta can

2938: [Poi2000]病毒

Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 1111 Solved: 556
[Submit][Status][Discuss]

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自動機,在不能走每個單詞最後一個字母的前提下,如果某個字符串在自動機上無法匹配,
    則說明可以找到無限長的字符串。
    為了方便起見,將所有的fail指針合並,最後在自動機上搜索就行了。 
*/ #include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; #define maxn 30010 int n,sz=1,a[maxn][2],fail[maxn],word[maxn]; bool ins[maxn],vis[maxn]; char s[maxn]; void insert(){ int now=1,len=strlen(s); for(int i=0;i<len;i++){
int t=s[i]-0; if(!a[now][t])a[now][t]=++sz; now=a[now][t]; } word[now]=1; } void acmach(){ queue<int>q; q.push(1);fail[1]=0; while(!q.empty()){ int now=q.front();q.pop(); for(int i=0;i<2;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]=1; for(int i=0;i<2;i++){ if(ins[a[x][i]])return 1; if(vis[a[x][i]]||word[a[x][i]])continue; vis[a[x][i]]=1; if(dfs(a[x][i]))return 1; } ins[x]=0; return 0; } int main(){ for(int i=0;i<2;i++)a[0][i]=1; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%s",s); insert(); } acmach(); if(dfs(1))printf("TAK"); else printf("NIE"); return 0; }

bzoj 2938: [Poi2000]病毒