AC自动机(模板无指针)

日常吐槽:哈哈哈哈哈哈哈我终于改完这个板了啊……竟然和主席树一样又是四天...不过还做了比赛,所以还是挺不错的。目前要学的字符串算法好像只差后缀自动机了,嗯,接下来要备战NOIP了呢。

  不过为什么暑假只有30天???八月还要集训???好像作业还没动???

思路

  其实就是在一颗Trie树上把多个字符串用类似于next数组的fail指针连成一个大的KMP。总而言之就是让被匹配的那一长串不停地往前匹配而不退回,然后就跳来跳去的咯,原理是和KMP一样的。更好地理解fail指针和如何实现移步https://blog.csdn.net/u013371163/article/details/60469145,不过博主写得实在是太可爱了=v=。

例题

  JZOJ1566 单词查找

Description

  给一个主串S以及M个字符串。问这M个字符串在主串中出现多少次。

Input

  第一行一个整数N,表示S的长度。
  第二行一个整数M,定义如题。
  下面M行,每行一个字符串,定义如题。
  下面一行N个字母,即主串S。

Output

  一个正整数,表示出现的次数。

Sample Input

10
3
a
aba
abc
abcabababa

Sample Output

9

Hint

【数据范围】
  对于40%的数据,1<=n<=10000,1<=m<=100
  对于100%的数据,1<=n<=2000000,1<=m<=3000,1<=l<=10
  保证所有字母都是英文小写字母。

代码

  造福人类的时间到了!网上的模板题50个有49个都!是!用!指!针!实!现!作为一名不用指针的忠实党已经痛苦得不想说话。感谢师兄的模板,救我于水火之中*v*

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int len, leng, n, tot = 0, ans = 0;
int w[30001], son[30001][26], fail[30001];
char s[2000001];
void Trie_build()
{
    int now = 0;
    for (int i = 0; i < len; i++)
    {
        int p = s[i] - 'a';
        if (!son[now][p])
            son[now][p] = ++tot;
        now = son[now][p];
    }
    w[now]++;
}
void AC_build()
{
    int q[30001], h = 0, t = 1;
    q[t] = 0;
    while (h != t)
    {
        h++;
        int head = q[h];
        for (int i = 0; i < 26; i++)
        {
            if (son[head][i])
            {
                q[++t] = son[head][i];
                if (!head)
                {
                    fail[son[head][i]] = 0;
                    continue;
                }
                int k = fail[head];
                while (k && !son[k][i])
                    k = fail[k];
                fail[son[head][i]] = son[k][i];
                w[son[head][i]] += w[son[k][i]];
            }
        }
    }
}
void AC_work()
{
    int head = 0;
    for (int i = 0; i < leng; i++)
    {
        int p = s[i] - 'a';
        if (son[head][p]) 
            head = son[head][p];
        else
        {
            int k = fail[head];
            while (k && !son[k][p])    k = fail[k];
            if (!son[k][p]) head = 0;
            else head = son[k][p];
        }
        ans += w[head];
    }
}
int main()
{
    memset(w, 0, sizeof w);
    memset(son, 0, sizeof son);
    memset(fail, 0, sizeof fail);
    scanf("%d%d", &leng, &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%s", s);
        len = strlen(s);
        Trie_build();
    }
    scanf("%s", s);
    AC_build();
    AC_work();
    printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zhy-AK/p/9340598.html