把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P3121 [USACO15FEB]Censoring G

题面传送门
因为上一题单串匹配是KMP+栈,所以这道题多串匹配考虑AC自动机+栈。
开一个栈记录当前没有被弹出的字符。同时记录匹配到了那个节点,在AC自动机上跑匹配即可。
注意有一个方法就是字符串结束标记上直接打上字符串长度这样就不用那么烦。
时间复杂度\(O(|S|+\sum{|T|})\)
代码实现:

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int n,m,k,x,y,z,sh,g[100039],now,cnt;
char s[100039],a[100039],st[100039];
struct AC{int son[26],fail,cnt;}f[100039];
inline void get(){
	register int i,now=0;
	for(i=1;i<=m;i++)now=(f[now].son[a[i]-'a']?f[now].son[a[i]-'a']:(f[now].son[a[i]-'a']=++cnt));
	f[now].cnt=m;
}
queue<int> q;
inline void bfs(){
	register int i;for(i=0;i<=25;i++)if(f[0].son[i]) q.push(f[0].son[i]);
	while(!q.empty()){
		now=q.front();q.pop();
		for(i=0;i<=25;i++){
			if(f[now].son[i]) f[f[now].son[i]].fail=f[f[now].fail].son[i],q.push(f[now].son[i]);
			else f[now].son[i]=f[f[now].fail].son[i];
		}
	}
}
int main(){
	freopen("1.in","r",stdin);
	register int i,j;
	scanf("%s",s+1);
	scanf("%d",&n);
	for(i=1;i<=n;i++)scanf("%s",a+1),m=strlen(a+1),get();
	m=strlen(s+1);now=0;bfs();
	for(i=1;i<=m;i++){
		now=g[sh];st[++sh]=s[i];
		now=f[now].son[s[i]-'a'];
		g[sh]=now;
		if(f[now].cnt){
			for(j=sh-f[now].cnt+1;j<=sh;j++)st[j]=0,g[j]=0;sh-=f[now].cnt;
		}
	}
	for(i=1;i<=sh;i++) putchar(st[i]);
}
posted @ 2021-02-03 15:42  275307894a  阅读(49)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end