bzoj2938: [Poi2000]病毒
传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2938
思路:构建AC自动机,无限长的安全代码就是能一直在AC自动机上匹配而匹配不上任何一个危险串。依旧是匹配指针不能走到危险串的结尾点x,fail指针指向x的y也不能走,因为根据fail的定义,x这个危险串是y的后缀。找出危险节点后就是找环了,有环就有无限长的安全代码,否则没有。
#include<cstdio> #include<cstring> #include<algorithm> const int maxn=30010; using namespace std; int n;char s[maxn]; struct AC_DFA{ int tot,ch[maxn][2],fail[maxn],q[maxn],head,tail;bool dang[maxn],bo[maxn],ins[maxn]; void insert(){ int p=0; for (int i=0;i<(int)strlen(s);p=ch[p][s[i]-'0'],i++) if (!ch[p][s[i]-'0']) ch[p][s[i]-'0']=++tot; dang[p]=1; } void getfail(){ head=0,q[tail=1]=0,fail[0]=-1; while (head!=tail){ int x=q[++head]; for (int i=0;i<=1;i++) if (ch[x][i]) q[++tail]=ch[x][i],fail[ch[x][i]]=x==0?0:ch[fail[x]][i],dang[ch[x][i]]|=dang[fail[ch[x][i]]]; else ch[x][i]=x==0?0:ch[fail[x]][i]; } } bool dfs(int x){ ins[x]=1; for (int i=0;i<=1;i++){ int v=ch[x][i]; if (ins[v]) return 1; if (bo[v]||dang[v]) continue; bo[v]=1; if (dfs(v)) return 1; } ins[x]=0;return 0; } }T; int main(){ scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%s",s),T.insert(); T.getfail(),puts(T.dfs(0)?"TAK":"NIE"); return 0; }