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

题目背景

通过套取数据而直接“打表”过题者,是作弊行为,发现即棕名。

这是一道简单的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;

题解

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 1e6 + 10;
char s[maxn];

namespace ac
{
int tot, ext[maxn], fail[maxn], trie[maxn][26];
queue<int> q;

void insert(char* s)
{
    int u = 0;
    for (int i = 1; s[i]; i++)
    {
        int c = s[i] - 'a';
        if (!trie[u][c]) trie[u][c] = ++tot;
        u = trie[u][c];
    }
    ext[u]++;
}

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

int query(char* t)
{
    int u = 0, res = 0;
    for (int i = 1; t[i]; i++)
    {
        u = trie[u][t[i] - 'a'];
        for (int j = u; j && ~ext[j]; j = fail[j])
        {
            res += ext[j];
            ext[j] = -1;
        }
    }
    return res;
}
}

int main()
{
    #ifdef ONLINE_JUDGE
    #else freopen("input.txt", "r", stdin);
    #endif
    int n;
    scanf("%d", &n);
    while (n--)
    {
        scanf("%s", s + 1);
        ac::insert(s);
    }
    scanf("%s", s + 1);
    ac::build();
    printf("%d\n", ac::query(s));
    return 0;
}
发布了370 篇原创文章 · 获赞 148 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_35850147/article/details/104120553