BZOJ 2938: [Poi2000]病毒 [AC自动机 拓扑排序]

2938: [Poi2000]病毒

题意:判断是否存在无限长的不含模式串的字符串。只有01.


建出套路DP的转移图,判断有环就行了

练习一下拓扑排序

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=3e4+5;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

int n; char s[N];
struct edge{int v, ne;}e[N];
int cnt=1, h[N], ind[N];
inline void ins(int u, int v) {e[++cnt]=(edge){v, h[u]}; h[u]=cnt; ind[v]++;}
namespace ac {
	struct meow{int ch[2], fail, val;} t[N];
	int sz;
	void insert(char *s) {
		int len=strlen(s+1), u=0;
		for(int i=1; i<=len; i++) {
			int c=s[i]-'0';
			if(!t[u].ch[c]) t[u].ch[c] = ++sz;
			u = t[u].ch[c];
		}
		t[u].val=1;
	}
	int q[N], head, tail;
	void build() {
		head=tail=1;
		for(int i=0; i<2; i++) if(t[0].ch[i]) q[tail++]=t[0].ch[i];
		while(head != tail) {
			int u=q[head++];
			t[u].val |= t[t[u].fail].val;
			for(int i=0; i<2; i++) {
				int &v=t[u].ch[i];
				if(!v) v = t[t[u].fail].ch[i];
				else t[v].fail = t[t[u].fail].ch[i], q[tail++]=v;
			}
		}
		for(int u=0; u<=sz; u++) if(!t[u].val) 
			for(int i=0; i<=1; i++) if(!t[t[u].ch[i]].val) ins(u, t[u].ch[i]);
	}
}
int st[N], top;
bool circle(int n) {
	for(int i=0; i<=n; i++) if(!ind[i]) st[++top]=i;
	int tot=0;
	while(top) {
		int u=st[top--]; tot++;
		for(int i=h[u];i;i=e[i].ne) {
			ind[e[i].v]--;
			if(!ind[e[i].v]) st[++top]=e[i].v;
		}
	}
	return tot != n+1;
}

int main() {
	freopen("in","r",stdin);
	n=read();
	for(int i=1; i<=n; i++) scanf("%s",s+1), ac::insert(s);
	ac::build();
	puts(circle(ac::sz) ? "TAK" : "NIE");
}
原文地址:https://www.cnblogs.com/candy99/p/6666607.html