题解:对于一组病毒编码,我们构建AC自动机。如果存在一个无限长的安全代码,它在里面匹配,将一直匹配不上,也就是说,失配边会形成一个环。
所以构建好AC自动机后dfs失配边看有无环即可。
上代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 30005 4 int n; char ch[N]; 5 struct acc 6 { 7 int f[N],next[N][2],cnt,head,tail,q[N]; 8 bool vis[N],ins[N],danger[N]; 9 acc(){ 10 cnt=0; 11 memset(vis,0,sizeof(vis)); 12 memset(ins,0,sizeof(ins)); 13 memset(danger,0,sizeof(danger)); 14 } 15 void inser(){ 16 scanf("%s",ch); int p=0,len=strlen(ch); 17 for(int a,i=0;i<len;i++){ 18 a=ch[i]-'0'; 19 if(!next[p][a]) next[p][a]=++cnt; 20 p=next[p][a]; 21 } danger[p]=1; 22 } 23 void getfail(){ 24 head=0; tail=0; 25 for(int i=0;i<2;i++) if(next[0][i]) q[tail++]=next[0][i],f[next[0][i]]=0; 26 //一定不要直接把0丢进队列BFS,要分别把每个单独拿出来,不然是错的 27 while(head<tail){ 28 int p=q[head++]; 29 for(int i=0;i<2;i++){ 30 int v=next[p][i]; 31 if(!v) {next[p][i]=next[f[p]][i]; continue;} 32 int k=f[p]; 33 while(k && !next[k][i]) k=f[k]; k=next[k][i]; 34 f[v]=k; 35 danger[v]|=danger[k]; 36 q[tail++]=v; 37 } 38 } 39 } 40 bool dfs(int x){ 41 ins[x]=1; 42 for(int i=0;i<2;i++){ 43 int v=next[x][i]; 44 if(ins[v]) return 1; 45 if(vis[v] || danger[v]) continue; 46 vis[v]=1; 47 if(dfs(v)) return 1; 48 } 49 ins[x]=0; 50 return 0; 51 } 52 }acm; 53 int main(){ 54 scanf("%d",&n); 55 for(int i=1;i<=n;i++) acm.inser(); 56 acm.getfail(); 57 if(acm.dfs(0)) puts("TAK"); 58 else puts("NIE"); 59 return 0; 60 }