P5357 AC自动机(二次加强版)

P5357 AC自动机(二次加强版)

题意:

给出一个文本串S和n个模式串,分别求出每个模式串在S中出现的次数。

思路:

多个模式串一个匹配串,标准的AC自动机,题目求每个模式串在文中出现的位置,可以在匹配文本串的时候,经过每个点都赋值为1,因为以该点为单词结尾一定存在该文本串中,但是因为可能该单词中包含其他单词,所以用拓扑排序,他的后缀加上当前单词出现的次数,就是那个后缀部分的出现次数。

实现:

#include <stdio.h>
#include <string.h>
const int N = 2e6 + 5;
int tr[N][26], idx = 1, nex[N], q[N], id[N], f[N];
char s[N];
void insert(int x)
{
    int p = 0;
    int len = strlen(s + 1);
    for (int i = 1; i <= len; i++)
    {
        int t = s[i] - 'a';
        if (!tr[p][t])
            tr[p][t] = idx++;
        p = tr[p][t];
    }
    id[x] = p;
}
void build()
{
    int hh = 1, tt = 0;
    for (int i = 0; i < 26; i++)
        if (tr[0][i])
            q[++tt] = tr[0][i];
    while (hh <= tt)
    {
        int t = q[hh++];
        for (int i = 0; i < 26; i++)
        {
            int &p = tr[t][i];
            if (!p)
                p = tr[nex[t]][i];
            else
            {
                nex[p] = tr[nex[t]][i];
                q[++tt] = p;
            }
        }
    }
}
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%s", s + 1);
        insert(i);
    }
    build();
    scanf("%s", s + 1);
    int len = strlen(s + 1);
    for (int i = 1, j = 0; i <= len; i++)
    {
        int t = s[i] - 'a';
        j = tr[j][t];
        f[j]++;
    }
    for (int i = idx - 1; i >= 1; i--)
        f[nex[q[i]]] += f[q[i]];
    for (int i = 1; i <= n; i++)
        printf("%d\n", f[id[i]]);
    return 0;
}

posted @ 2022-08-07 18:04  zxr000  阅读(44)  评论(0编辑  收藏  举报