首页 > 其他分享 >[题解]P2444 [POI2000] 病毒

[题解]P2444 [POI2000] 病毒

时间:2024-08-21 18:15:49浏览次数:4  
标签:危险 int 题解 tr POI2000 vis P2444 fail 节点

P2444 [POI2000] 病毒

题目核心是多模式匹配,所以考虑用对所有模式串建立AC自动机。

我们把自动机上,存在一个模式串作为前缀的节点,称作“危险节点”。

如果无限长的安全代码存在的话,匹配过程中Trie图上一定有节点会经过多次,即存在环;而且经过的所有节点都不是“危险节点”,否则就包含病毒代码段了。

所以我们只需要看Trie图上是否存在不包含危险节点的环,就能得到答案了。

可以用一个dfs实现这一过程。用\(vis\)来表示节点访问状态,初始全为\(0\):

  • \(vis[u]=0\):\(u\)未被访问过。
  • \(vis[u]=1\):\(u\)正在处理中。
  • \(vis[u]=-1\):从\(u\)出发找不到环。

如果只用\(0,1\)而不用\(-1\)来剪枝优化,时间复杂度可能由线性退化到指数级,将无法通过hack数据。

bool dfs(int u){
	if(vis[u]==1) return 1;
	if(vis[u]==-1) return 0;
	vis[u]=1;
	for(int i=0;i<C;i++)//C=2
		if(!en[tr[u][i]]&&dfs(tr[u][i]))
			return 1;//en[x]=1表示x是危险节点
	vis[u]=-1;
	return 0;
}

最后就是如何判断某个节点是不是危险节点,这个可以在get_fail()中处理出来。如果节点\(u\)是模式串的结尾,或者\(fail[u]\)是危险节点,那么\(u\)就是危险节点。

时间复杂度\(O(\sum|s|\times |\Sigma|)\)。

点击查看代码
#include<bits/stdc++.h>
#define N 30010//节点数(模式串总长)
#define C 2//字符集大小
using namespace std;
int n,tr[N][C],fail[N],cnt;
int q[N],head,tail,vis[N];
bool en[N];
string s;
void ins(string s){
	int p=0;
	for(char i:s){
		int c=i-'0';
		if(!tr[p][c]) tr[p][c]=++cnt;
		p=tr[p][c];
	}
	en[p]=1;
}
void get_fail(){
	head=0,tail=-1;
	for(int i=0;i<C;i++) if(tr[0][i]) q[++tail]=tr[0][i];
	while(head<=tail){
		int u=q[head++];
		for(int i=0;i<C;i++){
			int& v=tr[u][i];
			if(v) fail[v]=tr[fail[u]][i],q[++tail]=v,
				en[v]|=en[fail[v]];
			else v=tr[fail[u]][i];
		}
	}
}
bool dfs(int u){
	if(vis[u]==1) return 1;
	if(vis[u]==-1) return 0;
	vis[u]=1;
	for(int i=0;i<C;i++)
		if(!en[tr[u][i]]&&dfs(tr[u][i]))
			return 1;
	vis[u]=-1;
	return 0;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>s;
		ins(s);
	}
	get_fail();
	if(dfs(0)) cout<<"TAK\n";
	else cout<<"NIE\n";
	return 0;
}

标签:危险,int,题解,tr,POI2000,vis,P2444,fail,节点
From: https://www.cnblogs.com/Sinktank/p/18372217

相关文章

  • TCP通信之经典问题解决
    先看下面的代码,研究下执行后会出现什么?服务端:fromsocketimport*ip_port=('127.0.0.1',8003)buffer_size=1024sock_server=socket(AF_INET,SOCK_STREAM)sock_server.bind(ip_port)sock_server.listen(5)whileTrue:print('服务端建立连接...')conn,addr=soc......
  • P1972 [SDOI2009] HH的项链 题解
    前言这是一篇分块题解,大概的思路洛谷的题解里的巨佬讲的很清楚(我的思路其实和大佬的差不多),可以去看看qaq。因为苯人为了卡常魔改代码,所以在本题解的中间具体步骤展示部分仅展示魔改前的代码(也就是被卡常但是好看一点的代码),魔改后的代码(100pts)在文章最末展示。题意题面传送门......
  • 操作系统基础之磁盘及软考高级试题解析
    概述基本概念磁盘有正反两个盘面,每个盘面有多个同心圆,每个同心圆是一个磁道,每个同心圆又被划分为多个扇区,数据就被存在扇区中。磁头首先寻找到对应磁道,然后等到磁盘进行周期旋转到指定的扇区,才能读取到对应的数据。存取时间=寻道时间+等待时间盘面号(磁头号):0~M-1;由于一......
  • 信号量、PV操作及软考高级试题解析
    信号量在并发系统中,信号量是用于控制公共资源访问权限的变量。信号量用于解决临界区问题,使得多任务环境下,进程能同步运行。此概念是由荷兰计算机科学家Dijkstra在1962年左右提出的。信号量仅仅跟踪还剩多少资源可用,不会跟踪哪些资源是可用的。信号量机制,处理进程同步和互斥的问......
  • 题解:Codeforces Round 967 (Div. 2) B [思维/构造]
    B.GeneratePermutationtimelimitpertest:1.5secondsmemorylimitpertest:256megabytesinput:standardinputoutput:standardoutputThereisanintegersequence\(a\)oflength\(n\),whereeachelementisinitially\(-1\).Misukihastwoty......
  • [ABC133D] Rain Flows into Dams 题解
    思路其实就是一道数学题。设每座山的水量为$ans_i$,大坝的水量为$w_i$,则根据题意可以得到以下方程:$$\begin{cases}w_i=\frac{ans_i+ans_{i+1}}{2}&i<n\w_i=\frac{ans_i+ans_1}{2}&i=n\end{cases}$$所以只要求出任意一个$ans$就可以求出剩余的$ans$,这里我选择求$ans_1$的......
  • CF1264D1 题解
    blog。写一个题解区没有的蠢做法,不依赖dp但是很难转到HardVersion(对于已经确定的序列,深度有单调性。就是如果答案为\(x\),那么肯定能选出深度为\(1\simx\)的子序列。记\(\operatorname{check}_s(x)\)表示check序列\(s\)能否选出深度为\(x\)的子序列。考虑如何c......
  • 题解:AT_abc140_e [ABC140E] Second Sum
    思路:双向链表+组合数学(不过你要用单调栈也没人拦着你)我们现在先抛开题面,先换个思路。我们现在求:这个数能做多少个区间的次大值。我们现在设\(l1,l2,r1,r2\)分别为左边第一个比这个数大的id,第二个比这个数大的id,右边第一个比这个数大的id,第二个比这个数大的id。竟然是......
  • 题解:Codeforces Round 967 (Div. 2) [暴力/贪心]
    A.MakeAllEqualtimelimitpertest:1secondmemorylimitpertest:256megabytesinput:standardinputoutput:standardoutputYouaregivenacyclicarray\(a_1,a_2,\ldots,a_n\).Youcanperformthefollowingoperationon\(a\)atmost\(n-......
  • 题解 |栈| #中缀表达式求值!!!!#
    描述请写一个整数计算器,支持加减乘三种运算和括号。数据范围:0≤∣s∣≤1000≤∣s∣≤100,保证计算结果始终在整型范围内要求:空间复杂度: O(n)O(n),时间复杂度 O(n)O(n)示例1输入:"1+2"返回值:3示例2输入:"(2*(3-4))*5"返回值:-10示例3输入:"3+2*3*4-1"返回值:26一、使......