bzoj2938
AC自动机+trie图优化
很明显就是要一个串不能匹配到任何一个病毒,那么我们就建一个AC自动机
不能匹配的话也就是一个节点不能是单词结束节点,fail指针也不能是结束节点
然后就卡壳了。。。zz
我们把自动机建成trie图,也就是不存在的节点直接指向原来fail指针,然后我们只要在这个图上找有没有环就可以了。
因为ac自动机当不能继续匹配,也就是没有儿子节点,就会沿着fail指针走,否则就沿着儿子走,于是我们就把不存在的儿子指向fail,是一种优化,如果有一个无限长的串,也就是这个串能不停地匹配,不会走到危险节点,那么肯定就有环了,因为自动机是有限的。
#include<bits/stdc++.h> using namespace std; const int N = 30010; int n; char s[N]; struct acautomation { int root, cnt; int child[N][2], fail[N], danger[N], vis[N], inq[N]; void insert(char s[]) { int now = root; for(int i = 0; i < strlen(s); ++i) { int x = s[i] - '0'; if(!child[now][x]) child[now][x] = ++cnt; now = child[now][x]; } danger[now] = 1; } void build_fail() { queue<int> q; for(int i = 0; i < 2; ++i) if(child[root][i]) { q.push(child[root][i]); fail[child[root][i]] = 0; } while(!q.empty()) { int u = q.front(); q.pop(); for(int i = 0; i < 2; ++i) { int v = child[u][i]; if(!v) child[u][i] = child[fail[u]][i]; else { int now = fail[u]; while(now != root && !child[now][i]) now = fail[now]; fail[v] = child[now][i]; danger[v] |= danger[fail[v]]; q.push(v); } } } } bool dfs(int u) { inq[u] = 1; for(int i = 0; i < 2; ++i) { int v = child[u][i]; if(inq[v]) return true; if(danger[v] || vis[v]) continue; vis[v] = 1; if(dfs(v)) return true; } inq[u] = 0; return false; } } ac; int main() { scanf("%d", &n); for(int i = 1; i <= n; ++i) { scanf("%s", s); ac.insert(s); } ac.build_fail(); if(ac.dfs(0)) puts("TAK"); else puts("NIE"); return 0; }