bzoj2938——AhoCorasickAutoMata

8 篇文章 0 订阅
2 篇文章 0 订阅

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

我会拼AC自动机服不服:AhoCorasickAutoMata

就这么厉害

病毒代码,总长不超过30K……明显AC自动机吗……建出来建出来

题目要求一个无限长的安全子串,为什么能无限长呢,也就是说它在AC自动机上匹配模板永远匹配不到

等价于永远走不到一个val值为1的节点

那么只要判断AC自动机上是否存在一个由val=0的节点相连形成的环就可以了,加一个dfs即可

代码如下

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define red(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long

const int maxn = 30100;
const int sigmasize = 2;
char s[maxn];
int n;

struct AhoCorasickAutoMata{
	int sz;
	int ch[maxn][3];
	int val[maxn],f[maxn],ins[maxn],vis[maxn],last[maxn];
	
	AhoCorasickAutoMata() { sz=1; memset(ch[0], 0, sizeof(ch[0])); }
	int idx(char c) { return c-'0'; }
	
	void insert(char* s,int v){
		int u = 0, n = strlen(s);
		rep(i, 0, n-1) {
			int c = idx(s[i]);
			if(!ch[u][c]) {
				memset(ch[sz], 0, sizeof(ch[sz]));
				val[sz] = 0;
				ch[u][c] = sz++;
			}
			u = ch[u][c];
		}
		val[u] = v;
	}

	void getfail() {
		queue<int> q;
		f[0] = 0;
		rep(c, 0, sigmasize-1){
			int u = ch[0][c];
			if(u) { f[u] = 0; q.push(u); last[u] = 0; }
		}
		while(!q.empty()) {
			int r = q.front(); q.pop();
			rep(c, 0, sigmasize-1) {
				int u = ch[r][c];
				if(!u) {
					ch[r][c] = ch[f[r]][c];
					continue;
				}
				q.push(u);
				int v = f[r];
				while(v && !ch[v][c]) v = f[v];
				f[u] = ch[v][c];
				last[u] = val[f[u]] ? f[u] : last[f[u]];
				val[u] |= val[ch[v][c]];
			}
		}
	}

	bool dfs(int x) {
		ins[x] = 1;
		rep(i, 0, 1) {
			int v = ch[x][i];
			if(ins[v]) return 1;
			if(vis[v] || val[v]) continue;
			vis[v] = 1;
			if(dfs(v)) return 1;
		}
		ins[x] = 0;
		return 0;
	}
}ac;

int main() {
	scanf("%d", &n);
	char ch = getchar();
	rep(i, 1, n){
		scanf("%s", s);
		ac.insert(s, 1);
	}
	ac.getfail();
	if (ac.dfs(0)) printf("TAK\n");
	else printf("NIE\n");
	return 0;
}

新代码风格持续养成中==

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值