AC自动机

oj传送门
本质上是在trie树上套kmp的next数组(fail数组),用bfs按逐层遍历可以保证不重复和遗漏。

题目中要求出模式串重复次数,由于模式串自身较短,可以暴力失配找后缀匹配的模式串

update:题目已改成二次加强版,不能直接暴力失配找后缀匹配,需要先记录每次最大匹配到串,然后按照trie树深度从大到小,再进行失配找匹配后缀。
对于重复出现的模式串我们只记录第一次出现的位置。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+100;
struct node{
	int a[26];
	int id;
	int fail;
}ac[maxn];int tot;
string s;
string t[maxn];
int n,m;
int c[maxn];
inline void build_fail(){
	queue<int>q;
	ac[0].fail=0;
	for(int i=0;i<26;i++){
		if(ac[0].a[i]){
			ac[ac[0].a[i]].fail=0;
			q.push(ac[0].a[i]);
		}
	}
	while(!q.empty()){
		int u=q.front(),v;q.pop();
		for(int i=0;i<26;i++){
			if(ac[u].a[i]){
				v=ac[u].fail;
				while(v&&!ac[v].a[i])v=ac[v].fail;
				if(ac[v].a[i])v=ac[v].a[i];
				ac[ac[u].a[i]].fail=v;
				q.push(ac[u].a[i]);
			}
		} 
	}
}
int cnt[maxn];
int ans[maxn];
void ac_query(){
	int now=0;
	for(auto r:s){
		while(now&&!ac[now].a[r-'a'])
			now=ac[now].fail;
		if(ac[now].a[r-'a'])now=ac[now].a[r-'a'];
		cnt[now]++;
	}
}
struct Node{
	int id,dep;
}p[maxn];int tot2;
void dfs(int u,int dep){
	p[tot2++]=(Node){u,dep};
	for(int i=0;i<26;i++){
		if(ac[u].a[i])dfs(ac[u].a[i],dep+1);
	}
}
bool cmp(Node x,Node y){
	return x.dep>y.dep;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>t[i];
	memset(ac,0,sizeof ac);tot=0;
	for(int i=1;i<=n;i++){
		int now=0;
		for(auto r:t[i]){
			if(!ac[now].a[r-'a'])
				ac[now].a[r-'a']=++tot;
			now=ac[now].a[r-'a'];
		}
		if(!ac[now].id)ac[now].id=i;
		c[i]=ac[now].id;
	}
	build_fail();
	memset(ans,0,sizeof ans);
	cin>>s;
	ac_query();
	
	dfs(0,0);
	sort(p+1,p+tot+1,cmp);
	for(int i=1;i<=tot;i++){
		ans[ac[p[i].id].id]+=cnt[p[i].id];
		cnt[ac[p[i].id].fail]+=cnt[p[i].id];
	}
	for(int i=1;i<=n;i++){
		cout<<ans[c[i]]<<endl;
	}
	return 0;
}
posted @ 2022-07-26 23:34  xyc1719  阅读(28)  评论(0)    收藏  举报