BZOJ 2938: [Poi2000]病毒 AC自动机
2016-12-28 18:41
344 查看
Description
二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
示例:
例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。
任务:
请写一个程序:
l 读入病毒代码;
l 判断是否存在一个无限长的安全代码;
l 将结果输出
Input
第一行包括一个整数n,表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。
Output
你应在在文本文件WIN.OUT的第一行输出一个单词:
l TAK——假如存在这样的代码;
l NIE——如果不存在。
解析:
这题一看有好多个病毒片段就知道应该是AC自动机了,但是怎么样才能判断出是否存在无限长的安全码呢,不难发现,当且仅当构建出的AC自动机上有经过根节点且不含任何危险代码的环,用一个dfs判环就好了
【注】:代码中判环中的son[i]->match=true;是为了让下一次搜到这直接跳过,否则超时
二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
示例:
例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。
任务:
请写一个程序:
l 读入病毒代码;
l 判断是否存在一个无限长的安全代码;
l 将结果输出
Input
第一行包括一个整数n,表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。
Output
你应在在文本文件WIN.OUT的第一行输出一个单词:
l TAK——假如存在这样的代码;
l NIE——如果不存在。
解析:
这题一看有好多个病毒片段就知道应该是AC自动机了,但是怎么样才能判断出是否存在无限长的安全码呢,不难发现,当且仅当构建出的AC自动机上有经过根节点且不含任何危险代码的环,用一个dfs判环就好了
【注】:代码中判环中的son[i]->match=true;是为了让下一次搜到这直接跳过,否则超时
#include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<ctime> #include<cmath> #include<iostream> #include<iomanip> #include<algorithm> using namespace std; struct Trie { Trie *son[2],*fail; bool match; bool use; Trie() { memset(son,0,sizeof(son)); fail=NULL; match=use=0; } bool pc() { use=true; for(int i=0;i<=1;i++) { if(son[i]->use) return true; if(son[i]->match) continue; son[i]->match=true; if(son[i]->pc()) return true; } use=false; return false; } }*root=new Trie(); void my_insert(char *s) { Trie *o=root; while(*s) { int x=(*s)-'0'; if(!o->son[x]) o->son[x]=new Trie(); o=o->son[x]; s++; } o->match=true; } void bfs() { static Trie* dui[1200000]; int top=1,my_final=1; for(int i=0;i<2;i++) { if(root->son[i]) { dui[my_final++]=root->son[i]; root->son[i]->fail=root; } else root->son[i]=root; } while(top<my_final) { Trie *o=dui[top]; for(int i=0;i<2;i++) { if(o->son[i]) { dui[my_final++]=o->son[i]; o->son[i]->fail=o->fail->son[i]; } else o->son[i]=o->fail->son[i]; } top++; Trie *mid=o; while(mid!=root && !mid->match) mid=mid->fail; o->match=mid->match; } } char s[1000101]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",s); my_insert(s); } bfs(); if(root->pc()) printf("TAK\n"); else printf("NIE\n"); return 0; }
相关文章推荐
- [BZOJ 2096][Poi2010]Pilots
- HDU4758 AC自动机+DP (HDU4758与HDU2222)
- BZOJ3275 Number (最小割)
- BZOJ2809——[Apio2012]dispatching
- BZOJ2809——[Apio2012]dispatching
- AC自动机-一般算法实现
- bzoj1088[SCOI2005]扫雷
- bzoj1086[SCOI2005]王室联邦
- [BZOJ1087][SCOI2005]互不侵犯King(状压)[第二题]
- bzoj 1015 正难则反+并查集
- bzoj 1787 lca
- bzoj 1022 博弈 Anti-Nim(模板)
- bzoj 1034 伪田忌赛马
- bzoj 2464 BFS【水】
- 字符串的多模式匹配
- [bzoj1003] [ZJOI2006]物流运输trans
- [bzoj1500][NOI2005]维修数列
- [bzoj1208] [HNOI2004]宠物收养所
- [bzoj1269][AHOI2006]文本编辑器editort
- [bzoj1503][NOI2004]郁闷的出纳员