[bzoj2938][AC自动机]病毒

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Rose_max/article/details/82899394

Description

二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
示例: 例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11,
000000}为病毒代码段,那么就不存在一个无限长的安全代码。 任务: 请写一个程序: l 读入病毒代码; l
判断是否存在一个无限长的安全代码; l 将结果输出

Input

第一行包括一个整数n,表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。

Output

你应在在文本文件WIN.OUT的第一行输出一个单词: l TAK——假如存在这样的代码; l
NIE——如果不存在。

Sample Input

3

01

11

00000

Sample Output

NIE

题解

建出AC机
先把病毒传递一下…
在AC机上跑
我们的目标是两次合法跑到同一个状态,因为这样就可以无限循环了嘛…
那就大力跑啊…
不加传递会凉凉

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(int x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
inline void print(int x){write(x);printf(" ");}
struct node{int son[2],s,fail;}tr[31000];int root,trlen;
char ch[31000];
void add()
{
	int len=strlen(ch+1),p=root;
	for(int i=1;i<=len;i++)
	{
		int y=ch[i]-'0';
		if(!tr[p].son[y])tr[p].son[y]=++trlen;
		p=tr[p].son[y];
	}
	tr[p].s++;
}
queue<int> q;
void build_fail()
{
	q.push(0);
	while(!q.empty())
	{
		int x=q.front();q.pop();
		for(int i=0;i<=1;i++)
		{
			int y=tr[x].son[i];
			if(!y)continue;
			if(x==0)tr[y].fail=0;
			else
			{
				int j=tr[x].fail;
				while(j&&!tr[j].son[i])j=tr[j].fail;
				j=tr[j].son[i];tr[y].fail=j;
			}
			q.push(y);
		}
		if(tr[tr[x].fail].s)tr[x].s=1;
	}
}
bool v[31000],hh[31000];
bool ok(int x)
{
	if(tr[x].s)return false;
	if(v[x])return true;
	v[x]=true;
	for(int i=0;i<=1;i++)
	{
		int y=x;
		while(y&&!tr[y].son[i])y=tr[y].fail;
		y=tr[y].son[i];
		if(v[y])return true;
		if(hh[y])continue;hh[y]=1;
		if(ok(y))return true;
	}
	v[x]=false;
	return false;
}
int n;
int main()
{
	n=read();
	for(int i=1;i<=n;i++)scanf("%s",ch+1),add();
	build_fail();
	if(ok(0))puts("TAK");
	else puts("NIE");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/82899394