AC自动机学习笔记

AC自动机

Tags:字符串
作业部落


一、概述

\(Aho-Corasic\ automaton\),中文名\(AC\)自动机,是\(Trie\)图的一种,实现高效多串匹配单串的一种字符串算法
跟踪dalao的blog
\(Trie\)树上令一个点表示从根到它的串,那么一个点的fail指向和它拥有最长后缀的串(所以可以指向\(0\)

二、题单

三、做题经验

1
用来多串匹配单串或多串,效率高于\(KMP\)(可以代替),但是字符集很大时候需要大空间或用时间换空间(开\(set\)
2
套路:\(dp[i][j]\)表示到第\(i\)号节点(长串匹配到\(i\)),匹配长度为\(j\)(短串匹配到\(j\))的方案数啥的

四、Tip

! \(Fail\)是一棵树,但是\(AC\)自动机是\(Trie\)图,可以存在环(病毒
! 构造数据的时候,可以检查自己写的\(AC\)自动机是否可以从第一位开始匹配

五、模板

洛谷3808模板1
首先建出\(Trie\)树(\(Build\)),然后通过\(BFS\)算出\(Fail\),再进行匹配

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN=1000100;
struct Node{int ch[26],fail,end;}t[MAXN];
char s[MAXN];
int N,node;
queue<int> Q;
void Build()
{
    int len=strlen(s),x=0;
    for(int i=0;i<len;i++)
    {
        if(!t[x].ch[s[i]-'a']) t[x].ch[s[i]-'a']=++node;
        x=t[x].ch[s[i]-'a'];
    }
    t[x].end++;
}
void Get_Fail()
{
    for(int i=0;i<26;i++) if(t[0].ch[i]) Q.push(t[0].ch[i]);
    while(!Q.empty())
    {
        int x=Q.front();Q.pop();
        for(int i=0;i<26;i++)
            if(t[x].ch[i])
            {
                t[t[x].ch[i]].fail=t[t[x].fail].ch[i];
                Q.push(t[x].ch[i]);
            }
            else t[x].ch[i]=t[t[x].fail].ch[i];
    }
}
int AC()
{
    int len=strlen(s),x=0,ans=0;
    for(int i=0;i<len;i++)
    {
        x=t[x].ch[s[i]-'a'];
        for(int p=x;p&&~t[p].end;p=t[p].fail)
            ans+=t[p].end,t[p].end=-1;
    }
    return ans;
}
int main()
{
    cin>>N;while(N--){scanf("%s",s);Build();}
    Get_Fail();scanf("%s",s);
    printf("%d\n",AC());return 0;
}

六、一句话题解

[luogu3808]【模板】AC自动机(简单版)
把模式串的AC自动机建好后用文本串匹配,匹配完成就删去此串及其后缀

[luogu3796]【模板】AC自动机(加强版)
[CJOJ1435] 【模板题 USACO】AC自动机
[BZOJ3172][TJOI2013]单词
统计每个模式串出现次数,匹配时打个标记,然后用\(fail\)树DFS完成统计数量

[HDU2296]Ring
\(dp[i][j]\)表示母串匹配到第\(i\)位,匹配到AC自动机上第\(j\)个节点的最大权值,同时记录\(string\ qq[i][j]\)表示选择的方案

[BZOJ1030][JSOI2007]文本生成器
\(dp[i][j]\)表示生成文本长度为\(i\),匹配到AC自动机上第\(j\)个节点的没有出现认识的单词的方案数,最后用总方案减去所有不合法方案即为答案

[Luogu2444][POI2000]病毒Hard
如果AC自动机上出现了没有\(end\)标记的环那么就存在无限长的串使得不存在任何模式串

[BZOJ1009][HNOI2008]GT考试Hard
\(dp[i][j]\)表示长串枚举到\(i\)短串匹配到\(j\)的方案数,由于短串很短,所以另\(G[i][j]\)表示短串从上次匹配的\(s[i]\)下一位将要匹配\(k=1...9\)从而匹配/失配到了\(s[j]\)的方案数,使用矩阵乘法,\(F[0][0]=1,F*G\)表示枚举下一位数字是几来更新方案数

[BZOJ3530][SDOI2014]数数Hard
数位DP,\(dp[i][j][0/1/2]\)表示数字有\(i\)位,AC自动机上匹配到第\(j\)个节点,比\(N\)小/等/大的方案数,最后统计位数比\(N\)小的所有答案以及位数等于\(N\)\(0/1\)

[Luogu3121][USACO15FEB]审查CensoringHard
建好AC自动机后跑匹配,记录匹配母串中每个字符出现的位置,如果遇到\(end\)节点那么回到该词前一个字符的位置,继续向下匹配

[BZOJ1212][HNOI2004]L语言Hard
AC自动机:可以识别的是若干个区间,从起点起\(BFS\),能够被搜到的最右端节点即为答案
Trie树DP:字符串反转后建\(Trie树\)\(dp[i]\)表示\(s_{1..p}\)能否被识别,当\(s_{i..j}\)\(Trie\)树上的一个单词的时候\(dp[i]|=dp[j]\)

[Luogu3041][USACO12JAN]视频游戏的连击Video Game Combos
\(dp[i][j]\)表示母串长度为\(i\),匹配到AC自动机上第\(j\)个节点的最大分数

posted @ 2018-06-10 22:31  饕餮传奇  阅读(248)  评论(0编辑  收藏  举报