【POI2000】病毒

版权声明:小蒟蒻的博客转载也请注明出处哦 https://blog.csdn.net/qq_42835823/article/details/86663805

【POI2000】病毒

AC自动机

(注:POI  波兰OI)

洛谷地址

在这里插入图片描述
在这里插入图片描述
先建立AC自动机,一般的题都是要尽可能地匹配,而这道题是尽可能不匹配。

就用DFS找一下有无从根出发不经过危险节点(末尾标上val的节点),的一个环即可。
貌似在getfail()时就已经把一些儿子连到了失败指针的,具体的奥秘还不是很清楚。

注意:

  • 如果一个节点的失败指针是危险节点,那么这个点也是危险节点。
  • DFS时要记录两个数组,vis(是否在当前的环中,用完要清零),app(是否搜到过,不用清零),我们每次只搜索没出现过的节点,若搜到已在环中就表示找到环了,推出程序即可。


推荐:
T^T
(╯▽╰)


#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;
}

猜你喜欢

转载自blog.csdn.net/qq_42835823/article/details/86663805