洛谷 P5357 AC自动机 模板题

题目链接

题意

给出一个长串,提问n个串,输出在长串中出现的次数

题解

将n个询问的串建立AC自动机,拿长串去匹配
首先不能暴力跳 f a i l fail fail 去统计了,因为,答案的总和肯定是 n 2 n^2 n2 级别的,所以肯定不是暴力跳 f a i l fail fail 一个一个去累加答案的
根据 f a i l fail fail 的含义,如果当前结点匹配成功,那么他的 f a i l fail fail 指向的结点一定也匹配成功,同理, f a i l fail fail f a i l fail fail也出现一次
建立 f a i l 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]]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值