Solution [POI2000]病毒
题目大意:给定若干个模式串,问能否构造出一个无限长的文本串使得其不能被任何一个模式串匹配
AC自动机
分析:
首先AC自动机比较适合来搞多模匹配,我们将Trie树补全,补成一个图,然后我们文本串来做匹配就可以直接在Trie树上走了
在这种情况下,我们匹配文本串时直接沿着补全后的Trie树上的边走,走到底暴力跳fail指针,就可以把所有匹配它的模式串找出来
那么我们要使得没有一个模式串可以匹配文本串,就要求我们在Trie树上走到的点暴力跳fail指针能走到的点中没有一个点有标记,在这个前提下如果我们能够找到环的话就可以构造出无限长的文本串了
我们建出AC自动机,dfs找环就可以了
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 3e4 + 100;
namespace AC{
int ch[maxn][2],fail[maxn],val[maxn],f[maxn],vis[maxn],ins[maxn],tot,ans;
inline int idx(char c){return c - '0';}
inline void insert(char *str){
int u = 0;
for(int i = 1;str[i];i++){
int c = idx(str[i]);
if(!ch[u][c])ch[u][c] = ++tot;
u = ch[u][c];
}
val[u] = 1;
}
inline void build(){
queue<int> Q;
for(int i = 0;i < 2;i++)
if(ch[0][i])
Q.push(ch[0][i]);
while(!Q.empty()){
int u = Q.front();Q.pop();
for(int i = 0;i < 2;i++)
if(ch[u][i])fail[ch[u][i]] = ch[fail[u]][i],val[ch[u][i]] |= val[fail[ch[u][i]]],Q.push(ch[u][i]);
else ch[u][i] = ch[fail[u]][i];
}
}
inline void dfs(int u = 0){
if(ins[u])ans = 1;
if(vis[u] || val[u])return;
ins[u] = vis[u] = 1;
for(int i = 0;i < 2;i++)
dfs(ch[u][i]);
ins[u] = 0;
}
}
int n;
char str[maxn];
int main(){
scanf("%d",&n);
for(int i = 1;i <= n;i++)scanf("%s",str + 1),AC::insert(str);
AC::build();
AC::dfs();
puts(AC::ans ? "TAK" : "NIE");
return 0;
}