P3121 [USACO15FEB]Censoring G

P3121 [USACO15FEB]Censoring G

AC 自动机 多模式串匹配问题。

首先我们对所有模式串建立一个 ACAM 。

然后我们把文本串放上去匹配,当我们匹配到一个带标记的点的时候,说明我们目前出现了一个串,那么检查当前是否可以匹配完全,可以的话我们会直接相当于现在说明都没有匹配,也就是直接返回到根节点。

不然的话我们就按照可撤销并查集的思路,用一个栈记录一下我们的路径然后往回跳即可。

我们这里拿两个栈,一个记录上一个跳的编号,一个记录字符串。

最后直接把记录字符串的那个输出即可。

代码:

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;bool f=false;char ch=getchar();
	while(!isdigit(ch)){f=(ch=='-');ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) x=-x,putchar('-');
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
const int N=1e5+5;
int n,m;
struct ACAM{
	int son[26],fail,val;
	#define son(x,i) t[x].son[i]
	#define fail(x) t[x].fail
	#define val(x) t[x].val
}t[N];
int root,cur;
void Insert(char *str){
	int len=strlen(str),p=root;
	for(int i=0;i<len;i++){
		int c=str[i]-'a';
		if(!son(p,c)) son(p,c)=++cur;
		p=son(p,c);
	}
	val(p)=len;
	return ;
}
void Build(){
	queue<int> q;
	for(int i=0;i<26;i++) if(son(root,i)) fail(son(root,i))=root,q.push(son(root,i));
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=0;i<26;i++){
			if(son(x,i)) fail(son(x,i))=son(fail(x),i),q.push(son(x,i));
			else son(x,i)=son(fail(x),i);
		}
	}
	return ;
}
int sta1[N],sta2[N],top;
void Search(char *str){
	int len=strlen(str),now=root;
	for(int i=0;i<len;i++){
		int c=str[i]-'a';
		now=son(now,c);
		sta1[++top]=c;
		sta2[top]=now;
		if(val(now)){
			top-=val(now);
			if(top==0) now=0;
			else now=sta2[top];
		}
	}
	return ;
}
char a[N],st[N];
int main(){
	scanf("%s",a);
	read(n);
	for(int i=1;i<=n;i++){
		scanf("%s",st);
		Insert(st);
	}
	Build();
	Search(a);
	for(int i=1;i<=top;i++) putchar('a'+sta1[i]);
	return 0;
}
posted @ 2021-04-19 18:49  __Anchor  阅读(51)  评论(0编辑  收藏  举报