【BZOJ2938】病毒,AC自动机练习
来源:互联网 发布:姚明体测数据 编辑:程序博客网 时间:2024/06/05 18:39
传送门(权限题)
2938: [Poi2000]病毒
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 462 Solved: 240
[Submit][Status][Discuss]
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
写在前面:给了三个样例的良心题
思路:
我们首先确定,如果可能,那么符合条件的字符串中一定有一个循环的字符串,如果不可能,那一定没有循环的字符串(因为循环的字符串是有循环节的,如果没有循环的字符串,那就意味着所有的循环节都不可以,那就是没有符合条件的了,反之亦如此)
然后偷个懒
zky:
首先我们把所有串建一个AC自动机
方便起见我们直接把fail指针合并到子结点
如果一个串能无限长,也就是说它可以在AC自动机上一直进行匹配但就是匹配不上
也就是说匹配指针不能走到val为1的结点,设这个点为x
即root..x是一个病毒串
那么fail指针指向x的y也不能走
因为root..x是root..y的一个后缀
处理出来判断有向图是否有环
dfs即可
建fail时把那些当前节点i没有的字符(相当于失配状态)都转移到fail[i]上去,之后我们只要从根上出发dfs一通乱走,如果途中遇到字符串结束的标记节点,就不走(因为一走不就相当于有这个病毒了吗),如果最后无路可走(怎么选都要经过标记节点)那就NiE了,但如果我们能走出一个没有标记节点的环,那就说明我们可以找到一个循环节使字符串合法且无限延长下去了
注意:
DFS时注意及时退出,减少搜索树深度,用两个bool数组记录节点的搜索状态,其中一个表示这个点是否曾经搜索过,减少重复搜索;另一个表示这个点是否在我们目前想要的环的路径上(可能有点抽象,就是说我们是否已经经过这个点并且走在这个点所连接的边上,搜索完是要回溯的,而前一个bool数组只是单纯记录这个点是否走过,不必回溯更改)
代码:
#include<bits/stdc++.h>using namespace std;int root=1,tot=1,n;int trie[30002][2],fail[30002];bool num[30002],vis[30002],flag[30002];char s[30002];queue<int>q;void insert(char s[]){ int len=strlen(s),now=root; for (int i=0;i<len;i++) { if (!trie[now][s[i]-'0']) trie[now][s[i]-'0']=++tot; now=trie[now][s[i]-'0']; } num[now]=1;}void build(){ int now,tmp; q.push(root); while (!q.empty()) { now=q.front(); q.pop(); for (int i=0;i<2;i++) if (trie[now][i]) { tmp=fail[now]; while (tmp&&!trie[tmp][i]) tmp=fail[tmp]; if (tmp&&now!=root) fail[trie[now][i]]=trie[tmp][i], num[trie[now][i]]+=num[trie[tmp][i]]; else fail[trie[now][i]]=root; q.push(trie[now][i]); } else { if (now==root) trie[now][i]=root; else trie[now][i]=trie[fail[now]][i]; } }}void dfs(int x){ if (flag[x]) {printf("TAK");exit(0);} if (num[x]||vis[x]) return; if (x!=root)vis[x]=1; flag[x]=1; for (int i=0;i<2;i++) dfs(trie[x][i]); flag[x]=0;}main(){ scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%s",s), insert(s); build(); dfs(root); printf("NIE");}
- 【BZOJ2938】病毒,AC自动机练习
- AC自动机【poi2000】bzoj2938 病毒
- BZOJ2938: [Poi2000]病毒 AC自动机
- [bzoj2938][Poi2000]病毒 AC自动机
- BZOJ2938[Poi2000]病毒 AC自动机
- bzoj2938 [Poi2000]病毒 AC自动机+DP
- bzoj2938[Poi2000]病毒 AC自动机+dfs
- [BZOJ2938][Poi2000]病毒(AC自动机+拓扑排序)
- BZOJ2938 [Poi2000]病毒 解题报告【AC自动机】【DFS】
- BZOJ2938 POI2000 病毒 补全AC自动机 Trie图判环
- BZOJ2938【AC自动机】
- bzoj2938(ac自动机)
- 【练习05】 AC自动机 1001 病毒侵袭
- poj2778 & hdu 2243 AC自动机+矩阵 &&BZOJ2938
- bzoj2938病毒
- bzoj2938 病毒
- [模板练习]AC自动机
- 【AC自动机】 hdu2896 病毒侵袭
- GDOI'2016市选day2 —— 2. 选举(ele)
- 编程之美2.8找符合条件的整数
- java构造方法
- setDrawingCacheEnabled(boolean flag)的用法
- c++细节总结链接
- 【BZOJ2938】病毒,AC自动机练习
- 1到m的倒数和
- 利用Android传感器开发水平仪
- 【ZOJ 2562】 More Divisors
- 探究自定义View的测量
- 欢迎使用CSDN-markdown编辑器
- 百钱百鸡 枚举法
- tomcat服务器调优
- IDEA 配置优化 提高开发效率