BZOJ 2938: [Poi2000]病毒

2938: [Poi2000]病毒

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 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

Sample Output

NIE

HINT

 

Source

 
[Submit][Status][Discuss]

 

在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

 

posted @ 2017-01-13 11:04  YouSiki  阅读(236)  评论(0编辑  收藏  举报