版权声明:小蒟蒻的博客转载也请注明出处哦 https://blog.csdn.net/qq_42835823/article/details/86663805
【POI2000】病毒
AC自动机
(注:POI 波兰OI)
先建立AC自动机,一般的题都是要尽可能地匹配,而这道题是尽可能不匹配。
就用DFS找一下有无从根出发不经过危险节点(末尾标上val的节点),的一个环即可。
貌似在getfail()时就已经把一些儿子连到了失败指针的,具体的奥秘还不是很清楚。
注意:
- 如果一个节点的失败指针是危险节点,那么这个点也是危险节点。
- DFS时要记录两个数组,vis(是否在当前的环中,用完要清零),app(是否搜到过,不用清零),我们每次只搜索没出现过的节点,若搜到已在环中就表示找到环了,推出程序即可。
#include<bits/stdc++.h>
using namespace std;
const int M=1e5+5,N=3e4+5;
int n,siz=1,ch[N][2],val[N],fail[N];
char s[N];
void insert(){
int len=strlen(s+1);
int p=1;
for(int i=1;i<=len;i++){
int c=s[i]-'0';
if(!ch[p][c])ch[p][c]=++siz;
p=ch[p][c];
}
val[p]++;
}
void getfail(){
queue<int>q;
fail[1]=0;
for(int i=0;i<=1;i++)
if(ch[1][i]){
fail[ch[1][i]]=1;
q.push(ch[1][i]);
}
while(!q.empty()){
int c=q.front();q.pop();
for(int i=0;i<=1;i++){
int u=ch[c][i];
if(!u){
ch[c][i]=ch[fail[c]][i];//与失配指针连边
continue;
}
int v=fail[c];
fail[u]=ch[v][i];
if(val[ch[v][i]])val[u]=1;
q.push(u);
}
}
}
int vis[N],app[N];
void dfs(int x){
vis[x]=app[x]=1;
for(int i=0;i<=1;i++){
if(vis[ch[x][i]]){
printf("TAK");
exit(0);
}
else if(!val[ch[x][i]]&&!app[ch[x][i]])dfs(ch[x][i]);
}
vis[x]=0;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
insert();
}
getfail();//
dfs(1);
printf("NIE");
return 0;
}