【Luogu】 P2444 [POI2000]病毒

题目链接

点击打开链接

题目解法

看到有多串匹配,很大概率是 A C AC AC 自动机
先把 A C AC AC 自动机用 T r i e Trie Trie 图建出来

e d [ u ] ( 0 / 1 ) ed[u](0/1) ed[u](0/1) 表示 T r i e Trie Trie 图上的 u u u 节点是否存在前缀与后缀相同,且前缀是一个病毒代码段的全部,虽然描述起来比较烦,但做过基础题的话 e d ed ed 数组就很好理解了
如果字符串是有限的话,只要记录当前串与模板串的最长 b o r d e r border border 的尾结点,然后不能经过 e d ed ed 1 1 1 的点就可以了
拓展到无限长的话,只要能跳的点可以形成一个环就是 T A K TAK TAK,否则就是 N I E NIE NIE
找环的话用 d f s dfs dfs 就可以了

#include <bits/stdc++.h>
using namespace std;
const int N(30100);
int n;
char str[N];
int idx,tr[N][2],ne[N],ed[N];
bool vis[N];
inline int read(){
	int FF=0,RR=1;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
	for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
	return FF*RR;
}
void insert(){
	int len=strlen(str),p=0;
	for(int i=0;i<len;i++){
		int c=str[i]-'0';
		if(!tr[p][c]) tr[p][c]=++idx;
		p=tr[p][c];
	}
	ed[p]=1;
}
void build(){
	int hh=0,tt=-1,que[N];
	if(tr[0][0]) que[++tt]=tr[0][0];
	if(tr[0][1]) que[++tt]=tr[0][1];
	while(hh<=tt){
		int u=que[hh++];
		for(int i=0;i<2;i++){
			int v=tr[u][i];
			if(!v) tr[u][i]=tr[ne[u]][i];
			else ne[v]=tr[ne[u]][i],ed[v]|=ed[tr[ne[u]][i]],que[++tt]=v;
		}
	}
}
void dfs(int u){
	vis[u]=1;
	for(int i=0;i<2;i++){
		int v=tr[u][i];
		if(ed[v]) continue;
		if(vis[v]){
			puts("TAK");
			exit(0);
		}
		dfs(v);
	}
	vis[u]=0;
}
int main(){
	n=read();
	for(int i=1;i<=n;i++)
		scanf("%s",str),insert();
	build();
	dfs(0);
	puts("NIE");
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值