博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[BZOJ2938] 病毒
阅读量:5338 次
发布时间:2019-06-15

本文共 2563 字,大约阅读时间需要 8 分钟。

D. 病毒

题目描述

原题来自:POI 2000

二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。

示例:例如如果 {011,11,00000}\{011, 11, 00000\}{

011,11,00000} 为病毒代码段,那么一个可能的无限长安全代码就是 010101⋯010101\cdots 010101⋯。如果 {01,11,000000}\{01, 11, 000000\}{
01,11,000000} 为病毒代码段,那么就不存在一个无限长的安全代码。

请写一个程序,读入病毒代码,判断是否存在一个无限长的安全代码,将结果输出。

输入格式

第一行包括一个整数 nnn,表示病毒代码段的数目;

以下的 nnn 行,每一行都包括一个非空的 010101 字符串——就是一个病毒代码段。

输出格式

第一行输出一个单词。假如存在这样的代码,则输出 TAK,否则输出 NIE

样例

样例输入

301 11 00000

样例输出

NIE

数据范围与提示

对于全部数据,所有病毒代码段的总长度不超过 3×1044​​。

 

对trie图的理解还是没有那么透彻啊(以前就只是知道他比trie树快…)。

安全的串可以在AC自动机上在不匹配单词终点的情况下无限匹配(颓题解之前就想到这里), 在trie图上,如果能无线匹配那么意味着trie图上有环,dfs判环即可。

注意还有两个剪枝(zz的我刚开始居然用队列模拟深搜…):

1.单词终点不能走,那么fail指向单词终点的点也不能走。设一个单词终点为x,y->fail=x,那么root~x为root~y的后缀,y也不能走。将x设为危险节点,fail指向x的y也是危险节点,同理所有fail指向危险节点的点都是危险节点(之前一直不能理解这玩意儿有啥用),dfs时将危险节点剪掉。

2.由于一个节点可能会搜多次,所以将搜索过但是return 0的节点标记,剪掉。

#include
#include
using namespace std;struct trie{ int count; bool pd,danger,vis; trie *next[2],*fail; trie() { count=0;pd=0;danger=0;vis=0; next[1]=next[2]=fail=NULL; }}*q[100000],*root=new trie();int head,tail;void insert(char s[],trie *root){ trie *p=root; int i=0,index; while(s[i]) { index=s[i]-'0'; if(p->next[index]==NULL)p->next[index]=new trie(); p=p->next[index]; i++; } p->count++; p->danger=1;}void build_ac(trie *root){ q[++tail]=root; while(head!=tail) { trie *p=q[++head]; trie *temp=NULL; for(int i=0;i<=1;i++) if(p->next[i]) { if(p==root) p->next[i]->fail=p; else { p->next[i]->fail=p->fail->next[i]; if(p->fail->next[i]->danger)p->next[i]->danger=1; } q[++tail]=p->next[i]; } else if(p==root) p->next[i]=root; else p->next[i]=p->fail->next[i]; }}bool dfs(trie *p){ p->pd=1; for(int i=0;i<=1;i++) { if(p->next[i]->pd)return 1; if(p->next[i]->danger || p->next[i]->vis)continue; if(dfs(p->next[i]))return 1; p->next[i]->vis=1; } p->pd=0; return 0;}int n;char keyword[30010];char str[100000];signed main(){ //freopen("in.txt","r",stdin); cin>>n; for(int i=1;i<=n;i++) { scanf("%s",keyword); insert(keyword,root); } build_ac(root); if(dfs(root))cout<<"TAK"; else cout<<"NIE";}
View Code

 

转载于:https://www.cnblogs.com/Al-Ca/p/11056852.html

你可能感兴趣的文章
python 用数组实现队列
查看>>
认证和授权(Authentication和Authorization)
查看>>
Mac上安装Tomcat
查看>>
CSS3中box-sizing的理解
查看>>
传统企业-全渠道营销解决方案-1
查看>>
Lucene全文检索
查看>>
awk工具-解析1
查看>>
推荐一款可以直接下载浏览器sources资源的Chrome插件
查看>>
CRM product UI里assignment block的显示隐藏逻辑
查看>>
展望未来,总结过去10年的程序员生涯,给程序员小弟弟小妹妹们的一些总结性忠告...
查看>>
AMH V4.5 – 基于AMH4.2的第三方开发版
查看>>
Mac下安装npm全局包提示权限不够
查看>>
Web.Config文件配置之配置Session变量的生命周期
查看>>
mysql导入source注意点
查看>>
Python: 对于DataFrame.loc传入列表和传入元组输出区别的理解
查看>>
USACO / Sorting a Three-Valued Sequence (简单题,方法正确性待证)
查看>>
Android开发中 .9.png格式图形设计:
查看>>
Linux常见命令
查看>>
ASP.NET Page执行顺序如:OnPreInit()、OnInit()
查看>>
linux下编译安装nginx
查看>>