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;
}

浙公网安备 33010602011771号