luogu 3808 【模板】AC自动机(简单版)

http://www.elijahqi.win/archives/3227
题目背景

这是一道简单的AC自动机模板题。

用于检测正确性以及算法常数。

为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交。

管理员提示:本题数据内有重复的单词,且重复单词应该计算多次,请各位注意

题目描述

给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。

输入输出格式

输入格式:

第一行一个n,表示模式串个数;

下面n行每行一个模式串;

下面一行一个文本串。

输出格式:

一个数表示答案

输入输出样例

输入样例#1: 复制

2
a
aa
aa
输出样例#1: 复制

2
说明

subtask1[50pts]:∑length(模式串)<=10^6,length(文本串)<=10^6,n=1;

subtask2[50pts]:∑length(模式串)<=10^6,length(文本串)<=10^6;

建出AC自动机 然后将文本串在ACM上跑 统计答案的时候暴力跳fail表示求我这个点的后缀有多少是答案 但是因为fail树很多最后会汇流到一起而我们统计的是有几个出现所以统计之后要改成0

#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e6+10;char s[N];
int cnt=1,n,sum[N],fail[N],trans[N][26];
inline void insert1(char *s){
    static int p;p=1;
    for (int i=1,nxt;s[i];++i){
        if (!trans[p][s[i]-'a']) trans[p][s[i]-'a']=nxt=++cnt;
        else nxt=trans[p][s[i]-'a'];p=nxt;
    }++sum[p];
}
inline void buildAC(){
    queue<int>q;q.push(1);for (int i=0;i<26;++i) trans[0][i]=1;
    while(!q.empty()){
        int x=q.front();q.pop();
        for (int i=0;i<26;++i){
            int &y=trans[x][i];
            if (!y) {y=trans[fail[x]][i];continue;}
            fail[y]=trans[fail[x]][i];q.push(y);
        }
    }
}
int main(){
    freopen("luogu3808.in","r",stdin);
    scanf("%d",&n);int ans=0;
    for (int i=1;i<=n;++i) scanf("%s",s+1),insert1(s);
    scanf("%s",s+1);int p=1;buildAC();
    for (int i=1;s[i];++i){
        p=trans[p][s[i]-'a'];
        for (int j=p;j&&sum[j];j=fail[j]) ans+=sum[j],sum[j]=0;
    }printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值