BZOJ2938 [Poi2000]病毒 【AC自動機】
阿新 • • 發佈:2018-01-26
格式 指向 namespace ++ getch continue c++ sca 存在
題目
二進制病毒審查委員會最近發現了如下的規律:某些確定的二進制串是病毒的代碼。如果某段代碼中不存在任何一段病毒代碼,那麽我們就稱這段代碼是安全的。現在委員會已經找出了所有的病毒代碼段,試問,是否存在一個無限長的安全的二進制代碼。
示例:
例如如果{011, 11, 00000}為病毒代碼段,那麽一個可能的無限長安全代碼就是010101…。如果{01, 11, 000000}為病毒代碼段,那麽就不存在一個無限長的安全代碼。
任務:
請寫一個程序:
l 讀入病毒代碼;
l 判斷是否存在一個無限長的安全代碼;
l 將結果輸出
輸入格式
第一行包括一個整數n,表示病毒代碼段的數目。以下的n行每一行都包括一個非空的01字符串——就是一個病毒代碼段。所有病毒代碼段的總長度不超過30000。
輸出格式
你應在在文本文件WIN.OUT的第一行輸出一個單詞:
l TAK——假如存在這樣的代碼;
l NIE——如果不存在。
輸入樣例
3
01
11
00000
輸出樣例
NIE
題解
我們對所有串建出一個ACM,我們要做的就是在ACM上找一個路徑,使得路徑包含環且不包含結束節點
對於所有fail指針指向的節點,如果形成串,那麽該節點也不能選,因為fail指針指向的為當前串的前綴
建完機後跑一跑dfs檢查環就好了
#include<iostream>
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<‘ ‘; puts("");
using namespace std;
const int maxn = 300005,maxm = 1000005 ,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == ‘-‘) flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - ‘0‘; c = getchar();}
return out * flag;
}
int ch[maxn][2],siz,fail[maxn],val[maxn];
char s[maxn];
void insert(char* P){
int u = 0,len = strlen(P),x;
for (int i = 0; i < len; i++){
x = P[i] - ‘0‘;
if (!ch[u][x]) ch[u][x] = ++siz;
u = ch[u][x];
}
val[u] = 1;
}
void getfail(){
queue<int> q; fail[0] = -1;
for (int i = 0; i < 2; i++) if (ch[0][i]) q.push(ch[0][i]);
int u;
while (!q.empty()){
u = q.front(); q.pop();
for (int i = 0; i < 2; i++){
int v = ch[u][i];
if (!v) {ch[u][i] = ch[fail[u]][i]; continue;}
int k = fail[u];
fail[v] = ch[k][i];
val[v] |= val[ch[k][i]];
q.push(v);
}
}
}
bool flag;
int vis[maxn],ins[maxn];
bool dfs(int u){
ins[u] = true;
for (int i = 0; i < 2; i++){
int v = ch[u][i];
if (ins[v]) return true;
if (vis[v] || val[v]) continue;
vis[v] = true;
if (dfs(v)) return true;
}
ins[u] = false;
return false;
}
int main(){
int n = read();
while (n--) scanf("%s",s),insert(s);
getfail();
dfs(0) ? puts("TAK") : puts("NIE");
return 0;
}
BZOJ2938 [Poi2000]病毒 【AC自動機】