2938: [Poi2000]病毒
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 693 Solved: 360
[Submit][Status][Discuss]
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
01
11
00000
Sample Output
NIE
HINT
Source
在AC自动机上找不经过dangerous点的环。
1 #include <cstdio> 2 3 int tail = 1; 4 int dang[50005]; 5 int fail[50005]; 6 int next[50005][2]; 7 8 inline void insert(char *s) 9 { 10 int t = 1; 11 12 for (; *s; ++s) 13 { 14 int c = *s - '0'; 15 16 if (next[t][c] == 0) 17 next[t][c] = ++tail; 18 19 t = next[t][c]; 20 } 21 22 dang[t] = true; //dangerous node 23 } 24 25 inline void preworkFail(void) 26 { 27 static int que[100005], l, r; 28 29 fail[que[l = 0] = r = 1] = 0; 30 31 while (l != r) 32 { 33 int u = que[l++]; 34 35 for (int i = 0; i < 2; ++i) 36 { 37 if (next[u][i] == 0) 38 next[u][i] = next[fail[u]][i]; 39 else 40 { 41 int t = fail[u]; 42 43 while (next[t][i] == 0) 44 t = fail[t]; 45 46 fail[next[u][i]] = next[t][i]; 47 48 if (dang[next[t][i]]) 49 dang[next[u][i]] = true; 50 51 que[r++] = next[u][i]; 52 } 53 } 54 } 55 } 56 57 bool vis[50005]; 58 bool ins[50005]; 59 60 bool findCircle(int u) 61 { 62 ins[u] = true; 63 64 for (int i = 0, v; i < 2; ++i) 65 if (v = next[u][i]) 66 { 67 if (ins[v])return true; 68 if (vis[v] || dang[v])continue; 69 if (findCircle(v))return true; 70 } 71 72 vis[u] = true; 73 ins[u] = false; 74 75 return false; 76 } 77 78 signed main(void) 79 { 80 static int n; 81 static char str[30005]; 82 83 scanf("%d", &n); 84 85 next[0][1] = next[0][0] = 1; 86 87 for (int i = 1; i <= n; ++i) 88 scanf("%s", str), insert(str); 89 90 preworkFail(); 91 92 puts(findCircle(1) ? "TAK" : "NIE"); 93 }
@Author: YouSiki