Description
如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。
任务:
请写一个程序:
l 读入病毒代码;
l 判断是否存在一个无限长的安全代码;
l 将结果输出
Sample Input
3
01
11
00000
Sample Output
NIE
直接AC自动机即可。
建完后,跑一边AC机,看一下能不能跑出一个不经过病毒,并且循环的字符串即可。
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int _min(int x, int y) {return x < y ? x : y;}
int _max(int x, int y) {return x > y ? x : y;}
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
struct tnode {
int fail, s, son[2];
tnode() {memset(son, -1, sizeof(son));}
} t[31000]; int cnt;
queue<int> q;
int hh[31000];
char ss[31000];
bool v[31000];
void bt(int len) {
int x = 0;
for(int i = 1; i <= len; i++) {
int y = ss[i] - '0';
if(t[x].son[y] == -1) t[x].son[y] = ++cnt;
x = t[x].son[y];
} t[x].s = 1;
}
void get_fail() {
q.push(0);
while(!q.empty()) {
int x = q.front(); q.pop();
for(int i = 0; i <= 1; i++) {
int y = t[x].son[i];
if(y == -1) continue;
if(x == 0) t[y].fail = 0;
else {
int j = t[x].fail;
while(j && t[j].son[i] == -1) j = t[j].fail;
t[y].fail = _max(t[j].son[i], 0);
} q.push(y);
} if(t[t[x].fail].s == 1) t[x].s = 1;
}
}
bool dfs(int x) {
v[x] = 1;
for(int i = 0; i <= 1; i++) {
int j = x;
while(j && t[j].son[i] == -1) j = t[j].fail;
j = t[j].son[i];
if(j == -1) j = 0;
if(v[j]) return 1;
if(hh[j] || t[j].s == 1) continue;
hh[j] = 1;
if(dfs(j)) return 1;
}
v[x] = 0;
return 0;
}
int main() {
int n = read();
for(int i = 1; i <= n; i++) {
scanf("%s", ss + 1);
bt(strlen(ss + 1));
} get_fail();
if(dfs(0)) puts("TAK");
else puts("NIE");
return 0;
}