bzoj2938 AC自动机 + 拓扑排序找环

时间:2023-03-09 02:18:20
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=;register char c=getchar();for(;!isdigit(c);c=getchar());
for(;isdigit(c);now=now*+c-'',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-;
const int maxn = 5e4 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,K;
vector<int>Q[maxn];
int a[maxn];
struct AC{
int next[][],fail[];
int end[],ind[];;
int root,tot;
int newnode(){
next[tot][] = next[tot][] = -;
end[tot] = ; ind[tot] = ;
return tot++;
}
void init(){
tot = ;
root = newnode();
}
void insert(char *str){
int p = root;
for(int i = ;str[i]; i ++){
int id = str[i] - '';
if(next[p][id] == -) next[p][id] = newnode();
p = next[p][id];
}
end[p] = ;
}
void Build(){
queue<int>Q;
for(int i = ; i < ; i ++){
if(next[root][i] != -){
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 = ; i < ; i ++){
if(next[u][i] == -){
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]] = ;
}
Q.push(next[u][i]);
}
}
}
}
bool solve(){
for(int i = ; i < tot; i ++){
if(end[i]) continue;
ind[next[i][]]++;
ind[next[i][]]++;
}
queue<int>Q;
for(int i = ; i < tot; i ++){
if(!end[i] && !ind[i]) Q.push(i);
}
while(!Q.empty()){
int u = Q.front(); Q.pop();
for(int i = ; i < ; i ++){
ind[next[u][i]]--;
if(!end[next[u][i]] && !ind[next[u][i]])
Q.push(next[u][i]);
}
}
for(int i = ; i < tot; i ++){
if(!end[i] && ind[i]) return true;
}
return false;
}
}ac;
char str[maxn];
int main(){
Sca(N);
ac.init();
For(i,,N){
scanf("%s",str);
ac.insert(str);
}
ac.Build();
if(ac.solve()) puts("TAK");
else puts("NIE");
return ;
}