[Luogu P2444] [BZOJ 2938] [POI2000]病毒
阿新 • • 發佈:2018-11-25
洛谷傳送門
BZOJ傳送門
題目描述
二進位制病毒審查委員會最近發現瞭如下的規律:某些確定的二進位制串是病毒的程式碼。如果某段程式碼中不存在任何一段病毒程式碼,那麼我們就稱這段程式碼是安全的。現在委員會已經找出了所有的病毒程式碼段,試問,是否存在一個無限長的安全的二進位制程式碼。
示例:
例如如果 為病毒程式碼段,那麼一個可能的無限長安全程式碼就是 。如果 為病毒程式碼段,那麼就不存在一個無限長的安全程式碼。
任務:
請寫一個程式:
1.在文字檔案WIR.IN中讀入病毒程式碼;
2.判斷是否存在一個無限長的安全程式碼;
3.將結果輸出到檔案WIR.OUT中。
輸入輸出格式
輸入格式:
在文字檔案WIR.IN的第一行包括一個整數 ,表示病毒程式碼段的數目。以下的 行每一行都包括一個非空的 字串——就是一個病毒程式碼段。所有病毒程式碼段的總長度不超過 。
輸出格式:
在文字檔案WIR.OUT的第一行輸出一個單詞:
TAK
——假如存在這樣的程式碼;
NIE
——如果不存在。
輸入輸出樣例
輸入樣例#1:
3
01
11
00000
輸出樣例#1:
NIE
解題分析
一開始ZZ了, 然後發現把 邊加進來就是 自動機上找環…
注意通過fail下傳不能有的單詞的標記。
程式碼如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <queue>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 100500
int cnt, root, n;
int fail[MX], son[MX][2];
bool tag[MX], vis[MX], ins[MX];
char buf[MX];
std::queue <int> q;
void insert()
{
R int len = std::strlen(buf), now = root, id;
for (R int i = 0; i < len; ++i)
{
id = buf[i] - '0';
if (!son[now][id]) son[now][id] = ++cnt;
now = son[now][id];
}
tag[now] = true;
}
void build()
{
R int now;
if (son[0][0]) q.push(son[0][0]);
if (son[0][1]) q.push(son[0][1]);
W (!q.empty())
{
now = q.front(); q.pop();
for (R int i = 0; i < 2; ++i)
{
if (son[now][i])
{
fail[son[now][i]] = son[fail[now]][i];
tag[son[now][i]] |= tag[fail[son[now][i]]];
q.push(son[now][i]);
}
else son[now][i] = son[fail[now]][i];
}
}
}
void DFS(R int now)
{
if (ins[now]) puts("TAK"), exit(0);
if (vis[now]) return;
vis[now] = ins[now] = true;
if (!tag[son[now][0]]) DFS(son[now][0]);
if (!tag[son[now][1]]) DFS(son[now][1]);
ins[now] = false;
}
int main(void)
{
scanf("%d", &n);
W (n--) scanf("%s", buf), insert();
build();
DFS(0);
puts("NIE");
}