AC自动机+DFS 求条玄关 76pts TLEon#1 11 12 13
查看原帖
AC自动机+DFS 求条玄关 76pts TLEon#1 11 12 13
901471
five_rice_water楼主2025/1/8 15:18

改了一下午 对着题解对拍 发现tot少了200多 并且GetFail函数里面有一个2744节点反复进入队列 不知道为什么

//思路:
//假设现在有一个无限长的不包含题目要求的代码段的字符串
//那么把它放到AC自动机上面 就会发生如下的现象
//他会在AC自动机上绕圈 不会触发警报
//所以我们在AC自动机上找环就行了
#include<bits/stdc++.h>
using namespace std;
#define int short
const int N = 2e3+5;
const int M= 3e4+5;
string t[N];
int n,tot,tree[M][2],check[N],vis[N],res[N],fail[N];
void insert(string s,int id){
	int u = 0;
	for(int i = 0; i<s.size(); i++){
		int v = s[i]-'0';
		if(!tree[u][v]) tree[u][v]=++tot;
		u = tree[u][v];
	}
	check[u]=1;
}
void GetFail(){
	queue<int>q; 
	for(int i = 0; i<2; i++){
		if(tree[0][i]){
			q.push(tree[0][i]);
		}
	}
	while(!q.empty()){
		int tmp = q.front();
		q.pop();
		for(int i = 0; i<2; i++){
			if(tree[tmp][i]){
				q.push(tree[tmp][i]);
				fail[tree[tmp][i]] = tree[fail[tmp]][i];
			}
			else{
				tree[tmp][i]=tree[fail[tmp]][i];
			}
		}
		check[tmp]|=check[fail[tmp]];
	}
}
bool dfs(int x){
	vis[x]=1;
	for(int i = 0; i<2; i++){
		int v = tree[x][i];
		if(vis[v]) return 1;
		if(check[v] || res[v]) continue;
		res[v]=1;
		if(dfs(v)) return 1;
	}
	vis[x]=0;
	return 0;
}
signed main(){
	cin>>n;
	for(int i = 1; i<=n; i++){
		cin>>t[i];
		insert(t[i],i);
	}
	GetFail();
	int tmp = dfs(0);
	if(tmp) cout<<"TAK";
	else cout<<"NIE";
	return 0;
} 
2025/1/8 15:18
加载中...