【POI2000】病毒
Description
给定若干模式串,求是否存在一个无限长的文本串使得所有模式串均不能在此文本串中匹配。
Solution
这是一道AC自动机的变式,我们首先将这些模式串在Trie树上存储,以便AC自动机的操作。
我们这样思考:在我们存储Trie时,我们将每一个串的末尾标记一下,表示这是一个模式串的结尾,那么如果存在题目描述的文本串,那么意味着这个文本串在AC自动机上不会转移到任何一个标记节点,只会在一个环上不断转移,那么我们只需要找到这个环是否存在即可,很显然,找环可以从0节点dfs一遍。注意如果一个节点的fail节点如果是标记节点,那么它自身也是标记节点,因为该节点的fail节点到根节点的串是该节点到根节点的串的后缀。
所以我们只需要构造AC自动机,然后进行dfs即可。
Code
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int n; 5 char c[30010]; 6 int tot, ch[300100][2], f[300010], vis[300010], pd[300010], val[300010]; 7 void insert(char *a) { 8 int now = 0; 9 int l = strlen(a); 10 for (register int i = 0; i < l; ++i) { 11 if (!ch[now][a[i] - '0']) ch[now][a[i] - '0'] = ++tot; 12 now = ch[now][a[i] - '0']; 13 } 14 val[now] = 1; 15 } 16 queue <int> q; 17 void bfs() { 18 for (register int i = 0 ; i < 2; ++i) 19 if (ch[0][i]) { 20 f[ch[0][i]] = 0; 21 q.push(ch[0][i]); 22 } 23 while (!q.empty()) { 24 int now = q.front(); 25 q.pop(); 26 for (register int i = 0; i < 2; ++i) { 27 if (ch[now][i]) { 28 f[ch[now][i]] = ch[f[now]][i]; 29 val[ch[now][i]] |= val[f[ch[now][i]]]; 30 q.push(ch[now][i]); 31 } 32 else ch[now][i] = ch[f[now]][i]; 33 } 34 } 35 } 36 void dfs(int now) { 37 if (pd[now]) { 38 puts("TAK"); 39 exit(0); 40 } 41 if (vis[now] || val[now]) return ; 42 vis[now] = pd[now] = 1; 43 dfs(ch[now][0]); 44 dfs(ch[now][1]); 45 pd[now] = 0; 46 } 47 int main() { 48 scanf("%d", &n); 49 for (register int i = 1; i <= n; ++i) { 50 scanf("%s", c); 51 insert(c); 52 } 53 bfs(); 54 dfs(0); 55 puts("NIE"); 56 return 0; 57 }