[bzoj2938][AC自動機]病毒
阿新 • • 發佈:2018-12-12
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;
}