「洛谷P2444」病毒

image
洛谷\(link\)

分析:

先想想:如果构造出一个无限长的安全代码 再到 \(AC\) 自动机去匹配 会出现什么情况\(?\)
那当一位位匹配时 永远不会跳到某个病毒代码的结尾位置 然后 \(AC\) 自动机就会一直原地\(tp\)

记病毒代码的结尾位置为 危险标记 因为匹配到结尾已表明出现了病毒代码段
所以 问题就变成 在 \(trie\) 图上找一个环 并且环上没有危险标记

而且要注意 从根节点出发 不经过任何危险标记 也能到达这个环
如果节点\(x\)\(fail\)有危险标记 那这个点\(x\)也是危险的 因为\(fail\)\(x\)后缀

CODE:

点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define reg register
using namespace std;
typedef long long ll;
const int N=3e4+5;
struct Trie{
	int fail,num[2];
	bool in;
}trie[N];
int n,tot;
queue<int> q;
char ch[N];
bool vis[N],book[N];
void ins(char a[])
{
	int len=strlen(a),now=0;
	for(int i=0;i<len;i++)
	{
		int qwq=a[i]-'0';
		if(!trie[now].num[qwq]) trie[now].num[qwq]=++tot;
		now=trie[now].num[qwq];
	}
	trie[now].in=true;
}
void AC()
{
	if(trie[0].num[0]>0) q.push(trie[0].num[0]);
	if(trie[0].num[1]>0) q.push(trie[0].num[1]);
	while(!q.empty())
	{
		int now=q.front();
		q.pop();
		for(int i=0;i<=1;i++)
		{
			if(trie[now].num[i]>0)
			{
				q.push(trie[now].num[i]);
				int k=trie[now].fail;
				while(k&&trie[k].num[i]==0) k=trie[k].fail;
				if(trie[k].num[i]==0) trie[trie[now].num[i]].fail=0;
				else{
					trie[trie[now].num[i]].fail=trie[k].num[i];
					if(trie[trie[k].num[i]].in) trie[trie[now].num[i]].in=1;
				}
			}else trie[now].num[i]=trie[trie[now].fail].num[i];
		}
	}
}
void dfs(int x)
{
	vis[x]=1;
	for(int i=0;i<=1;i++)
	{
		if(vis[trie[x].num[i]]){puts("TAK");exit(0);}
		else if(!trie[trie[x].num[i]].in&&!book[trie[x].num[i]])
		{
			book[trie[x].num[i]]=1;
			dfs(trie[x].num[i]);
		}
	}
	vis[x]=0;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",ch);
		ins(ch);
	}
	AC(); dfs(0);
	puts("NIE");
	return 0;
}
posted @ 2022-01-21 11:47  EschatonRin  阅读(20)  评论(0)    收藏  举报