2021.11.10 [POI2000]病毒(AC自动机)

2021.11.10 [POI2000]病毒(AC自动机)

https://www.luogu.com.cn/problem/P2444

题意:

二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。

示例:

例如如果 {011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是 010101 …。如果 {01, 11, 000000} 为病毒代码段,那么就不存在一个无限长的安全代码。

现在给出所有的病毒代码段,判断是否存在无限长的安全代码。

分析:

建完trie后,在带有fail的图上跑一圈,看看存不存在环。存在环就可以,不存在环就不可以。

代码如下:

PS:POI是波兰的!

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;

const int N=3e4+10;
int n;
char s[N];
namespace trie{
	int t[N][2],fail[N],vis[N],endi[N],f[N],tot;
	int circle=0;
	queue<int>q;
	inline void insert(char *s){
		int n=strlen(s),u=0;
		for(int i=0;i<n;i++){
			int v=s[i]-'0';
			if(!t[u][v])t[u][v]=++tot;
			u=t[u][v];
		}
		endi[u]=1;
	}
	inline void build(){
		for(int i=0;i<2;i++)if(t[0][i])q.push(t[0][i]);
		while(!q.empty()){
			int u=q.front();q.pop();
			for(int i=0;i<2;i++){
				if(t[u][i]){
					fail[t[u][i]]=t[fail[u]][i],q.push(t[u][i]);
					if(endi[fail[t[u][i]]])endi[t[u][i]]=1;
				}else t[u][i]=t[fail[u]][i];
			}
		}
	}
	inline void dfs(int x){
		if(circle)return ;
		vis[x]=1;
		for(int i=0;i<2;i++){
			int v=t[x][i];
			if(vis[v])return (void)(circle=1);
			if(endi[v]||f[v])continue;
			f[v]=1;
			dfs(v);
		}
		vis[x]=0;
	}
} 

int main(){
	cin>>n;
	for(int i=1;i<=n;i++)scanf("%s",s),trie::insert(s);
	//scanf("%s",s);
	trie::build();
	trie::dfs(0);
	if(trie::circle)cout<<"TAK";
	else cout<<"NIE";
	return 0;
}
上一篇:链接:https://ac.nowcoder.com/acm/problem/22228来源:牛客网题目描述 在给定的数组中删除一个数。输入描述:多组测试。每组第一行输入1个整数n(n


下一篇:AtCoder Beginner Contest 174 题解