一年多没写过trie 和 ac自动机真是有点吃力鸭。。。。
我们先把trie建出来,顺便把AC自动机的边也都建好。
首先,有一些点是不可以走的,不仅仅是叶子节点,还有到根的链构成的字符串有某个后缀正好和某个叶子到根的链构成的字符串相同的。
这一步处理可以在AC自动机构建的时候顺带做好,考虑f[x]一直递归下去可以扫到x到根构成的链的字符串的所有后缀。
然后再dfs就可以了,交叉边不用走(想一想为什么),再不走禁止的那些点,如果dfs到回边的话就返回true,恩然后就ok了;
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=33335; int c[N][2],f[N],n,num; bool v[N],ist[N]; inline void ins(){ char ch=getchar(); while(ch!='0'&&ch!='1') ch=getchar(); int now=0,p; for(;ch=='0'||ch=='1';now=c[now][p],ch=getchar()){ p=ch-'0'; if(!c[now][p]) c[now][p]=++num; } v[now]=1; } inline void get_fail(){ queue<int> q; int x,r,u; if(c[0][0]) q.push(c[0][0]); if(c[0][1]) q.push(c[0][1]); while(!q.empty()){ x=q.front(),q.pop(); if(v[f[x]]) v[x]=1; for(int j=0;j<2;j++) if(!c[x][j]) c[x][j]=c[f[x]][j]; else{ u=c[x][j],f[u]=c[f[x]][j]; q.push(u); } } } bool dfs(int x){ if(ist[x]) return 1; if(v[x]) return 0; // cout<<x<<endl; v[x]=1,ist[x]=1; if(dfs(c[x][0])||dfs(c[x][1])) return 1; ist[x]=0; return 0; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) ins(); get_fail(); // for(int i=0;i<=num;i++) printf("%d %d %d %d ",i,f[i],c[i][0],c[i][1]); if(dfs(0)) puts("TAK"); else puts("NIE"); return 0; }