洛谷 P3808 【模板】AC自动机(简单版)

题目背景

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

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

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

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

题目描述

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

输入输出格式

输入格式:
第一行一个n,表示模式串个数;

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

下面一行一个文本串。

输出格式:
一个数表示答案

输入输出样例

输入样例#1:
2
a
aa
aa
输出样例#1:
2

分析:一道ac自动机的裸题。不过每个模式串只算一次。今天被字符串题虐得好惨呀,只能回来填坑了。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>

const int maxn=1e6+7;

using namespace std;

char s[maxn];
int n,cnt;

struct node{
    int fail,end;
    int vis[26];
}t[maxn];

void build(char s[maxn])
{
    int len=strlen(s);
    int now=0;
    for (int i=0;i<len;i++)
    {
        if (!t[now].vis[s[i]-'a']) t[now].vis[s[i]-'a']=++cnt;
        now=t[now].vis[s[i]-'a'];
    }
    t[now].end++;
}

void getfail()
{
    queue <int> q;
    for (int i=0;i<26;i++)
    {
        if (t[0].vis[i])
        {
            t[t[0].vis[i]].fail=0;
            q.push(t[0].vis[i]);
        }
    }
    while (!q.empty())
    {
        int u=q.front();
        q.pop();
        for (int i=0;i<26;i++)
        if (t[u].vis[i])
        {
            t[t[u].vis[i]].fail=t[t[u].fail].vis[i];
            q.push(t[u].vis[i]);
        }
        else
        {
            t[u].vis[i]=t[t[u].fail].vis[i];
        }
    }
}

int find(char s[maxn])
{
    int ans=0;
    int now=0;
    int len=strlen(s);
    for (int i=0;i<len;i++)
    {
        now=t[now].vis[s[i]-'a'];
        for (int k=now;k&&(t[k].end!=-1);k=t[k].fail)
        {
            ans+=t[k].end;
            t[k].end=-1;
        }
    }
    return ans;
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%s",s);
        build(s);
    }
    getfail();
    scanf("%s",s);
    printf("%d",find(s));
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/79993767