题意
给出一个长串,提问n个串,输出在长串中出现的次数
题解
将n个询问的串建立AC自动机,拿长串去匹配
首先不能暴力跳 fail 去统计了,因为,答案的总和肯定是 n2 级别的,所以肯定不是暴力跳 fail 一个一个去累加答案的
根据 fail 的含义,如果当前结点匹配成功,那么他的 fail 指向的结点一定也匹配成功,同理, fail 的 fail也出现一次
建立 fail 树, 长串去匹配时,在出现的结点 +1 ,然后根据拓扑序,将数值传递为儿子,最后就知道答案了
代码
#include<bits/stdc++.h>
#define N 2000010
#define INF 0x3f3f3f3f
#define eps 1e-6
#define pi acos(-1.0)
#define mod 998244353
#define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define bug(x) cerr<<#x<<" : "<<x<<endl
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
int w[N],in[N],id[N];
vector<int> G[N],ans;
struct Trie{
int t[N][26],fail[N],d[N];
int tot;
void ins(char* x,int g){
int i=0;
for(int j=0;x[j];j++){
int c=x[j]-'a';
if(!t[i][c]) t[i][c]=++tot;
i=t[i][c];
}
d[i]++;id[g]=i;
}
void get_fail(){
queue<int> q;
for (int i=0;i<26;i++) if (t[0][i]) q.push(t[0][i]);
while(!q.empty()) {
int i=q.front();q.pop();
for(int j=0;j<26;j++) {
if (t[i][j]){
fail[t[i][j]]=t[fail[i]][j];
q.push(t[i][j]);
}else
t[i][j]=t[fail[i]][j];
}
}
}
void AC_automation(char *x){
int i=0;
for(int j=0;x[j];j++) {
i=t[i][x[j]-'a'];
w[i]++;
}
}
void work(){
for(int i=1;i<=tot;i++) G[i].pb(fail[i]),in[fail[i]]++;
queue<int>q;
for(int i=1;i<=tot;i++) if(!in[i]) q.push(i);
while(!q.empty()){
int x=q.front();q.pop();
for(auto i:G[x]){
w[i]+=w[x];
in[i]--;
if (!in[i]) q.push(i);
}
}
}
}T1;
char t[N],s[N];
int main(){
int n;
sc(n);
for(int i=1;i<=n;i++){
scanf("%s",s);
T1.ins(s,i);
}
T1.get_fail();
scanf("%s",t);
T1.AC_automation(t);
T1.work();
for(int i=1;i<=n;i++) printf("%d\n",w[id[i]]);
}