[Poi2000] 病毒
2938: [Poi2000]病毒
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 1633 Solved: 835
[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
01
11
00000
Sample Output
NIE
HINT
题意:
给你$n$个01串,问是否存在一个无限长的串使得这$n$个串都不是它的子串。
题解:
建立$AC$自动机,那么若满足题意当且仅当在$AC$自动机上存在一个环不经过任意一个$end$节点,$dfs$找环即可。
找环时注意:(对所有图论问题均有)
- 存在环的条件不仅是$u\rightarrow v$中的$v$被遍历过,它还要在当前遍历序列中!(主要是我又一次忘了把$vis_u$标记清0)
- 若当前$u$的出边被遍历完并且没有找到环,说明$u$一定不在任何一个环上(反证),所以可以直接把它$delete$掉。
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; #define MAXN 100005 #define MAXM 500005 #define ll long long struct node{ int son[2]; bool ise,vis,ok; }tree[MAXN]; int tot=1,nxt[MAXN]; bool flag;char str[MAXN]; inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline void add(char *str){ int N=strlen(str),u=1; for(int i=0;i<N;i++){ int ch=str[i]-'0'; if(!tree[u].son[ch]) tree[u].son[ch]=++tot; u=tree[u].son[ch]; } tree[u].ise=1; return; } inline void get_nxt(){ for(int i=0;i<2;i++) tree[0].son[i]=1; queue<int> q; q.push(1); while(!q.empty()){ int u=q.front();q.pop(); for(int i=0;i<2;i++){ if(tree[u].son[i]){ q.push(tree[u].son[i]); nxt[tree[u].son[i]]=tree[nxt[u]].son[i]; tree[tree[u].son[i]].ise|=tree[nxt[tree[u].son[i]]].ise; } else tree[u].son[i]=tree[nxt[u]].son[i]; } } return; } inline int dfs(int u){ tree[u].vis=tree[u].ok=1; for(int i=0;i<2;i++){ int v=tree[u].son[i]; if(tree[v].vis || (!tree[v].ok && !tree[v].ise && dfs(v))) return 1; } tree[u].vis=0; return 0; } int main(){ int N=read(); for(int i=1;i<=N;i++) scanf("%s",str),add(str); get_nxt(); if(dfs(1)) printf("TAK\n"); else printf("NIE\n"); return 0; }