【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 }
2938: [Poi2000]病毒
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 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
01
11
00000
Sample Output
NIE