2938: [Poi2000]病毒
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
这道题容易想到我们只需要找到一个串它复制一遍,也不存在任意一个代码段,问题在于,我们如何确定是否存在这一个串。
我们可以建立一个后缀自动机,然后把不是结尾的节点通过失配边构成一个图,如果这个图上存在一个环,那么就说明存在一个串,它无论怎样复制也无法构成任意一个代码段。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 #include<string> 8 #include<map> 9 #include<queue> 10 #include<vector> 11 #include<set> 12 #define inf 1000000000 13 #define maxn 100000+5 14 #define maxm 10000+5 15 #define eps 1e-10 16 #define ll long long 17 #define for0(i,n) for(int i=0;i<=(n);i++) 18 #define for1(i,n) for(int i=1;i<=(n);i++) 19 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 20 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 21 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go) 22 using namespace std; 23 int read(){ 24 int x=0,f=1;char ch=getchar(); 25 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 26 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 27 return x*f; 28 } 29 int n,tot=1,cnt,t[maxn][2],danger[maxn],point[maxn]; 30 int in[maxn],head[maxn],num; 31 queue<int> q; 32 char ch[maxm]; 33 struct edge{ 34 int go,next; 35 }e[maxn]; 36 void ins(int u,int v){ 37 e[++cnt].go=v;e[cnt].next=head[u];head[u]=cnt; 38 } 39 void insert(){ 40 int len=strlen(ch),now=1; 41 for0(i,len-1){ 42 if(!t[now][ch[i]-'0'])t[now][ch[i]-'0']=++tot; 43 now=t[now][ch[i]-'0']; 44 } 45 danger[now]=1; 46 } 47 void build(){ 48 q.push(1); 49 while(!q.empty()){ 50 int x=q.front();q.pop();danger[x]|=danger[point[x]]; 51 for0(i,1){ 52 int tmp=point[x]; 53 while(tmp&&!t[tmp][i])tmp=point[tmp]; 54 if(t[x][i]){ 55 point[t[x][i]]=tmp?t[tmp][i]:1; 56 q.push(t[x][i]); 57 }else t[x][i]=tmp?t[tmp][i]:1; 58 } 59 } 60 } 61 bool topsort(){ 62 int num=0; 63 for1(i,tot) 64 for0(j,1) 65 if(!danger[i]&&!danger[t[i][j]]) 66 ins(i,t[i][j]),in[t[i][j]]++; 67 for1(i,tot) 68 if(!in[i]) 69 q.push(i); 70 while(!q.empty()){ 71 int x=q.front();q.pop();num++; 72 for4(i,x){ 73 in[y]--; 74 if(!in[y])q.push(y); 75 } 76 } 77 return num==tot; 78 } 79 int main(){ 80 //freopen("input.txt","r",stdin); 81 //freopen("output.txt","w",stdout); 82 n=read(); 83 for1(i,n){ 84 scanf("%s",ch); 85 insert(); 86 } 87 build(); 88 printf("%s\n",topsort()?"NIE":"TAK"); 89 return 0; 90 }