[POI2000]病毒
如果存在一个环,且环上没有任何危险标记(即病毒代码段末尾一位的结点专门作的编号),此时 AC自动机 能一直在环上匹配,并且永远也不会得到为模式串的一个子串, 这个找环可以通过 dfs 来实现
在构造失配指针时,一个很明显的优化是:如果一个结点拥有了失配指针,它指向的结点如果有危险标记,自己必然也危险,因为它到根结点形成的串是自己到根节点的后缀。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, cnt;
int vis[N], ins[N];
string a[2005];
struct str {
int end;
int fail;
int ch[2];
} AC[25000];
void build(string s) {
int now = 0;
for(int i = 0; i < s.size(); i++) {
if(!AC[now].ch[s[i] - '0'])
AC[now].ch[s[i] - '0'] = ++cnt;
now = AC[now].ch[s[i] - '0'];
}
AC[now].end = 1;
}
void Get_fail() {
queue<int> q;
int now = 1;
for(int i = 0; i <= 1; i++)
if(AC[0].ch[i])
AC[AC[0].ch[i]].fail = 0, q.push(AC[0].ch[i]);
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = 0; i <= 1; i++) {
if(AC[u].ch[i]) {
AC[AC[u].ch[i]].fail = AC[AC[u].fail].ch[i];
AC[AC[u].vis[i]].end |= AC[AC[AC[u].vis[i]].fail].end;
q.push(AC[u].ch[i]);
}
else AC[u].ch[i] = AC[AC[u].fail].ch[i];
}
}
}
void dfs(int x) {
if(ins[x]) {cout << "TAK\n"; exit(0);}
if(AC[x].end || vis[x]) return ;
vis[x] = ins[x] = 1;
dfs(AC[x].ch[0]);//注意这里不要判断( if(AC[x].ch[0]) )因为一个安全的代码可以不在trie树上~~趴~~
dfs(AC[x].ch[1]);
ins[x] = 0;
}
int main() {
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i];
build(a[i]);
}
Get_fail(); dfs(0);
cout << "NIE\n";
return 0;
}