题目描述
二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
示例:
例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。
任务:
请写一个程序:
l 读入病毒代码;
l 判断是否存在一个无限长的安全代码;
l 将结果输出
输入
第一行包括一个整数n,表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。
输出
你应在在第一行输出一个单词:
l TAK——假如存在这样的代码。
l NIE——如果不存在。
样例输入
3
01
11
00000
样例输出
NIE
题解
多模式串匹配问题。
果断AC自动机(因为蒟蒻我也不会别的啊QAQ)
把每个病毒串插进trie树,get_fail这些基本操作大家想必都会啦
本题多了一个奇诡操作:fail环。
首先了解一下fail环
拉过来一张丑陋的图:
![](https://img2018.cnblogs.com/blog/1605877/201906/1605877-20190625120236039-1231281743.png)
如上图为题目描述中为NIE的那个数据(好像少了个0……)。
![](https://img2018.cnblogs.com/blog/1605877/201906/1605877-20190625115746952-941477032.png)
显然上图中虚线表示的0并不存在。
所以dfs搜到他的时候,这个点指向root的右儿子的那个1的左儿子。
![](https://img2018.cnblogs.com/blog/1605877/201906/1605877-20190625120028115-499484797.png)
不过遗憾的是
这个0也不存在。
那么只好走这个1的fail指针,即root的右儿子,
然后我们发现,它还是会从root的右儿子去找到当前这个虚线框里的0
这次这个0指向了root的左儿子。
![](https://img2018.cnblogs.com/blog/1605877/201906/1605877-20190625120409397-80927164.png)
然后再顺下来我们发现又可以找到原来的1啦。
这就是fail环啦(至少我是这么理解的,大神别踩啊QAQ)
然后捏?
我们把插入时的endd设置成危险节点,
即不能访问的节点
然后一遍dfs就出来啦!
代码:
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
#define rint register int
using namespace std;
char ch[30004];
int n;
int trie[30004][2];
int cnt=1,fail[30004];
bool endd[30004],vis[30004];
bool ans=false,failed[30004];
inline void insert(char *str)
{
int len=strlen(str),p=1;
for(rint i=0;i<len;++i)
{
int l=str[i]-'0';
if(!trie[p][l])
trie[p][l]=++cnt;
p=trie[p][l];
}
endd[p]=true;
}
inline void get_fail()
{
queue <int>q;
q.push(1);
fail[1]=0;
trie[0][0]=trie[0][1]=1;
while(!q.empty())
{
int l=q.front();q.pop();
for(rint i=0;i<2;++i)
{
if(trie[l][i])
{
fail[trie[l][i]]=trie[fail[l]][i];
if(endd[fail[trie[l][i]]])
endd[trie[l][i]]=true;//注意这两句话,没加毁人生QAQ
q.push(trie[l][i]);
}
else trie[l][i]=trie[fail[l]][i];
}
}
}
inline void dfs(int u)
{
vis[u]=1;
for(int i=0;i<=1;i++)
{
if(vis[trie[u][i]])
{
ans=true;
return ;
}
else if(!failed[trie[u][i]]&&!endd[trie[u][i]])
{
failed[trie[u][i]]=1;
dfs(trie[u][i]);
}
}
vis[u]=0;
return ;
}
int main()
{
// freopen("wir213.in","r",stdin);
scanf("%d",&n);
for(rint i=1;i<=n;++i)
{
scanf("%s",ch);
insert(ch);
}
get_fail();
// for(rint i=1;i<=cnt;++i)cout<<fail[i]<<endl;
dfs(1);
if(ans)cout<<"TAK"<<endl;
else cout<<"NIE"<<endl;
return 0;
}
完结撒花~