首页 > 代码库 > BZOJ2938: [Poi2000]病毒

BZOJ2938: [Poi2000]病毒

传送门

AC自动机上的各种处理一直让我很迷。一个主要懵逼的点是不清楚对于不存在的字母所对应的方案如何处理。做了两道题大概比较清楚了。

其实对于不存在的字母节点不需要特殊的处理。因为如果累加方案的话,其方案会自动累加到$root$节点。而其fail指针也会自动指向自己。

 

另外这道题的判环参考了黄学长的代码,类似于一个简化版的tarjan。

 

 

//BZOJ 2938//by Cydiater//2016.10.18#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <string>#include <cstring>#include <iomanip>#include <queue>#include <map>#include <ctime>#include <algorithm>using namespace std;#define ll long long#define up(i,j,n)		for(int i=j;i<=n;i++)#define down(i,j,n)		for(int i=j;i>=n;i--)const int MAXN=1e6+5;const int oo=0x3f3f3f3f;inline int read(){	char ch=getchar();int x=0,f=1;	while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}	while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}	return x*f;}int N,len,next[MAXN][2],fail[MAXN],cnt=0,head,tail,q[MAXN];bool end[MAXN],vis[MAXN],ins[MAXN];char s[MAXN];namespace solution{	void insert(){		int now=0;		up(i,1,len){			int num=s[i]-‘0‘;			if(!next[now][num])next[now][num]=++cnt;			now=next[now][num];		}		end[now]=1;	}	void init(){		N=read();		memset(end,0,sizeof(end));		up(i,1,N){			scanf("%s",s+1);			len=strlen(s+1);			insert();		}	}	void buildAC(){		head=1;tail=0;		up(i,0,1)if(next[0][i])q[++tail]=next[0][i];		for(;head<=tail;head++){			int now=q[head];end[now]|=end[fail[now]];			up(i,0,1){				int son=next[now][i];				if(son>0){					fail[son]=next[fail[now]][i];					q[++tail]=son;				}				else next[now][i]=next[fail[now]][i];			}		}	}	bool dfs(int node){		ins[node]=1;		up(i,0,1){			int son=next[node][i];			if(ins[son])return 1;			if(vis[son]||end[son])continue;			vis[son]=1;			if(dfs(son))return 1;		}		ins[node]=0;		return 0;	}	void slove(){		buildAC();		memset(vis,0,sizeof(vis));		if(dfs(0))puts("TAK");		else      puts("NIE");	}}int main(){	using namespace solution;	init();	slove();	return 0;}

BZOJ2938: [Poi2000]病毒