bzoj 2938 [Poi2000]病毒 AC自动机
[Poi2000]病毒
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 1319 Solved: 659
[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
题解:
首先我们把所有串建一个AC自动机
方便起见我们直接把fail指针合并到子结点
如果一个串能无限长,也就是说它可以在AC自动机上一直进行匹配但就是匹配不上
也就是说匹配指针不能走到val为1的结点,设这个点为x
即root..x是一个病毒串
那么fail指针指向x的y也不能走
因为root..x是root..y的一个后缀
处理出来判断有向图是否有环
1 #include<cstring> 2 #include<iostream> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstdio> 6 #include<queue> 7 8 #define N 30007 9 using namespace std; 10 inline int read() 11 { 12 int x=0,f=1;char ch=getchar(); 13 while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} 14 while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 15 return x*f; 16 } 17 18 int n,m,cnt=1; 19 bool flag[N],ans,ins[N]; 20 struct Node 21 { 22 int c[2],suf; 23 bool flag; 24 }trie[N]; 25 char ch[N]; 26 27 void insert() 28 { 29 int now=1,len=strlen(ch); 30 for (int i=0;i<len;i++) 31 { 32 if (!trie[now].c[ch[i]-'0']) trie[now].c[ch[i]-'0']=++cnt; 33 now=trie[now].c[ch[i]-'0']; 34 } 35 trie[now].flag=true; 36 } 37 void make_AC() 38 { 39 for (int i=0;i<2;i++) 40 trie[0].c[i]=1; 41 queue<int>q;while(!q.empty()) q.pop(); 42 trie[1].suf=0; 43 q.push(1); 44 while(!q.empty()) 45 { 46 int u=q.front();q.pop(); 47 for (int i=0;i<2;i++) 48 if (trie[u].c[i]) 49 { 50 trie[trie[u].c[i]].suf=trie[trie[u].suf].c[i]; 51 if (trie[trie[trie[u].c[i]].suf].flag) trie[trie[u].c[i]].flag=true; 52 q.push(trie[u].c[i]); 53 } 54 else trie[u].c[i]=trie[trie[u].suf].c[i]; 55 } 56 } 57 void dfs(int u) 58 { 59 ins[u]=true; 60 for (int i=0;i<2;i++) 61 { 62 int v=trie[u].c[i]; 63 if (ins[v]) ans=true; 64 if (trie[v].flag||flag[v]) continue; 65 flag[v]=true; 66 dfs(v); 67 } 68 ins[u]=false; 69 } 70 int main() 71 { 72 n=read(); 73 for (int i=1;i<=n;i++) 74 { 75 scanf("%s",ch); 76 insert(); 77 } 78 make_AC(),dfs(1); 79 if (ans) printf("TAK\n"); 80 else printf("NIE\n"); 81 }