bzoj2938 AC自动机 + 拓扑排序找环
https://www.lydsy.com/JudgeOnline/problem.php?id=2938
题意:给出N个01病毒序列,询问是否存在一个无限长的串不存在病毒序列
正常来说,想要寻找一个串是否出现这些01序列可以直接跑AC自动机,这题反向问有没有无限长的不出现,说明在AC自动机上询问的时候,要避免经过所有病毒串标记的end结点以及需要寻找一个可以无限跑的环。
所以我们将字典树的边和失配指针的边都看作是一条有向边,如果存在一个环上没有病毒结尾的标记,那么他就是合法的。
值得一提的是,fail指针的意义是指向最长公共前后缀的下一个结点,因此如果一个节点的fail指针指向了一个危险结点,则这个结点也是危险的,因为他指向的点一定是他的后缀。
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; inline int read(){int now=0;register char c=getchar();for(;!isdigit(c);c=getchar()); for(;isdigit(c);now=now*10+c-'0',c=getchar());return now;} #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; const double eps = 1e-9; const int maxn = 5e4 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,K; vector<int>Q[maxn]; int a[maxn]; struct AC{ int next[2000010][2],fail[2000010]; int end[2000010],ind[2000010];; int root,tot; int newnode(){ next[tot][0] = next[tot][1] = -1; end[tot] = 0; ind[tot] = 0; return tot++; } void init(){ tot = 0; root = newnode(); } void insert(char *str){ int p = root; for(int i = 0;str[i]; i ++){ int id = str[i] - '0'; if(next[p][id] == -1) next[p][id] = newnode(); p = next[p][id]; } end[p] = 1; } void Build(){ queue<int>Q; for(int i = 0 ; i < 2; i ++){ if(next[root][i] != -1){ fail[next[root][i]] = root; Q.push(next[root][i]); }else{ next[root][i] = root; } } while(!Q.empty()){ int u = Q.front(); Q.pop(); for(int i = 0 ; i < 2; i ++){ if(next[u][i] == -1){ next[u][i] = next[fail[u]][i]; }else{ fail[next[u][i]] = next[fail[u]][i]; if(end[fail[next[u][i]]]){ end[next[u][i]] = 1; } Q.push(next[u][i]); } } } } bool solve(){ for(int i = 0 ; i < tot; i ++){ if(end[i]) continue; ind[next[i][0]]++; ind[next[i][1]]++; } queue<int>Q; for(int i = 0 ; i < tot; i ++){ if(!end[i] && !ind[i]) Q.push(i); } while(!Q.empty()){ int u = Q.front(); Q.pop(); for(int i = 0 ; i < 2; i ++){ ind[next[u][i]]--; if(!end[next[u][i]] && !ind[next[u][i]]) Q.push(next[u][i]); } } for(int i = 0 ; i < tot; i ++){ if(!end[i] && ind[i]) return true; } return false; } }ac; char str[maxn]; int main(){ Sca(N); ac.init(); For(i,1,N){ scanf("%s",str); ac.insert(str); } ac.Build(); if(ac.solve()) puts("TAK"); else puts("NIE"); return 0; }