【BZOJ】【2938】【POI2000】病毒

AC自动机


  好题>_<(其实是一次AC有些感动)

  嗯要找到无限长的一个字符串不包含任何一个模板串,就意味着在AC自动机(Trie图)上找到一个不经过任何一个危险结点的环,深搜一下就好了……记得离开某个结点的时候要清除标记!有点像tarjan……

 1 /**************************************************************
 2     Problem: 2938
 3     User: Tunix
 4     Language: C++
 5     Result: Accepted
 6     Time:68 ms
 7     Memory:3528 kb
 8 ****************************************************************/
 9  
10 //BZOJ 2938
11 #include<vector>
12 #include<cstdio>
13 #include<cstring>
14 #include<cstdlib>
15 #include<iostream>
16 #include<algorithm>
17 #define rep(i,n) for(int i=0;i<n;++i)
18 #define F(i,j,n) for(int i=j;i<=n;++i)
19 #define D(i,j,n) for(int i=j;i>=n;--i)
20 #define pb push_back
21 using namespace std;
22 inline int getint(){
23     int v=0,sign=1; char ch=getchar();
24     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
25     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
26     return v*sign;
27 }
28 const int N=1e5+10,INF=~0u>>2;
29 typedef long long LL;
30 /******************tamplate*********************/
31 struct Trie{
32     int ch[2],fail;
33     bool sign;
34 }T[N];
35 char s1[N];
36 int cnt=1,Q[N];
37 void ins(){
38     scanf("%s",s1);
39     int x=1,y;
40     rep(i,strlen(s1)){
41         y=s1[i]-'0';
42         if (!T[x].ch[y]) T[x].ch[y]=++cnt;
43         x=T[x].ch[y];
44     }
45     T[x].sign=1;
46 }
47 void make_fail(){
48     int l=0,r=-1;
49     Q[++r]=1;
50     while(l<=r){
51         int x=Q[l++],y,j;
52         T[x].sign|=T[T[x].fail].sign;
53         rep(i,2){
54             j=T[x].fail;
55             while(j && T[j].ch[i]==0) j=T[j].fail;
56             if (T[x].ch[i]){
57                 y=T[x].ch[i];
58                 T[y].fail=j ? T[j].ch[i] : 1;
59                 Q[++r]=y;
60             }else T[x].ch[i]=j ? T[j].ch[i] : 1;
61         }
62     }
63 }
64 bool vis[N],in[N];
65 bool dfs(int x){
66     if (vis[x]) return 0;
67     bool ans=0;
68     if (T[x].sign) return 0;
69     vis[x]=in[x]=1;
70     rep(i,2){
71         if (in[T[x].ch[i]]) return 1;
72         if (!T[T[x].ch[i]].sign) ans|=dfs(T[x].ch[i]);
73     }
74     in[x]=0;
75     return ans;
76 }
77 int main(){
78 #ifndef ONLINE_JUDGE
79     freopen("2938.in","r",stdin);
80     freopen("2938.out","w",stdout);
81 #endif
82     int n=getint();
83     F(i,1,n) ins();
84     make_fail();
85     if (dfs(1)) puts("TAK");
86     else puts("NIE");
87     return 0;
88 }
View Code

2938: [Poi2000]病毒

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 155  Solved: 87
[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

Sample Output

NIE

HINT

Source

[Submit][Status][Discuss]
posted @ 2015-04-06 20:48  Tunix  阅读(304)  评论(0编辑  收藏  举报