【BZOJ】【P2938】【Poi2000】【病毒】【题解】【AC自动机】

来源:互联网 发布:阿里免费h5建站 编辑:程序博客网 时间:2024/05/01 13:46

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2938

这题写题解的人好像不多的样子……

首先我们把所有串建一个AC自动机

方便起见我们直接把fail指针合并到子结点

如果一个串能无限长,也就是说它可以在AC自动机上一直进行匹配但就是匹配不上

也就是说匹配指针不能走到val为1的结点,设这个点为x

即root..x是一个病毒串

那么fail指针指向x的y也不能走

因为root..x是root..y的一个后缀

处理出来判断有向图是否有环

dfs即可

Code:

#include<bits/stdc++.h>using namespace std;int n;char s[30001];struct node{int id,val;node *go[2],*fail,*last;node(node *C=0){id=0;fail=C;val=0;last=C;for(int i=0;i<2;i++)go[i]=C;}}*Null,*root;node *newnode(node *C){static int cnt=0;node *x=new node(C);x->id=++cnt;return x;}void insert(const char *s){node *u=root;int len=strlen(s);for(int i=0;i<len;i++){int v=s[i]-'0';if(u->go[v]==Null)u->go[v]=newnode(root);u=u->go[v];}u->val=1;}void get_fail(){queue<node*>q;for(int i=0;i<2;i++)if(root->go[i]!=Null)q.push(root->go[i]),root->go[i]->fail=root->go[i]->last=root;while(!q.empty()){node *u=q.front(),*v;q.pop();for(int i=0;i<2;i++)if((v=u->go[i])!=Null){q.push(v);node *j=u->fail;while(j!=Null&&j->go[i]==Null)j=j->fail;v->fail=j->go[i];v->val|=v->fail->val;v->last=v->fail->val?v->fail:v->fail->last;}else u->go[i]=u->fail->go[i];}}short vis[30001*2];short ins[30001*2];bool dfs(node *u){ins[u->id]=1;node *v;for(int i=0;i<2;i++){v=u->go[i];if(v->val)continue;if(ins[v->id])return 1;if(vis[v->id])continue;vis[v->id]=1;if(dfs(v))return 1;}ins[u->id]=0;return false;}int main(){Null=newnode(0);Null->fail=Null;Null->last=Null;for(int i=0;i<2;i++)Null->go[i]=Null;root=Null;scanf("%d",&n);for(int i=1;i<=n;++i)scanf("%s",s),insert(s);get_fail();vis[1]=1;puts(dfs(root)?"TAK":"NIE");return 0;}



0 0
原创粉丝点击