1. 程式人生 > >[bzoj2938][AC自動機]病毒

[bzoj2938][AC自動機]病毒

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; }