码迷,mamicode.com
首页 > 其他好文 > 详细

AC自动机学习小结

时间:2019-01-10 18:20:27      阅读:135      评论:0      收藏:0      [点我收藏+]

标签:小结   tps   return   break   read   pos   讲解   struct   大写   

AC自动机

简要说明

  • \(AC\) 自动机,全称 \(Aho-Corasick\ automaton\) ,是一种有限状态自动机,应用于多模式串匹配.在 \(OI\) 中通常搭配 \(dp\) 食用.因为它是状态自动机.
  • 感性理解:在 \(Trie\) 树上加上 \(fail\) 指针.具体的讲解可以去看dalao们的博客(因为我实在是太菜了讲不好).

题目

  • 题目:给若干个模式串,再给一个文本串,问有几个模式串在文本串中出现过.
  • 板子题.注意一个模式串只被计算一次,统计后做上标记.
  • 这里采用的是补全 \(Trie\) 树的写法.
View code

#include"bits/stdc++.h"
using namespace std;
typedef long long LoveLive;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>‘9‘||jp<‘0‘)&&jp!=‘-‘)
        jp=getchar();
    if (jp==‘-‘)
        {
            fh=-1;
            jp=getchar();
        }
    while (jp>=‘0‘&&jp<=‘9‘)
        {
            out=out*10+jp-‘0‘;
            jp=getchar();
        }
    return out*fh;
}
const int MAXN=5e5+10;
const int Siz=26;
struct AhoCorasick{
    int idx;
    int ch[MAXN][Siz];
    int fail[MAXN];
    int val[MAXN];
    void init()
        {
            idx=0;
            memset(val,0,sizeof val);
            memset(ch,0,sizeof ch);
            memset(fail,0,sizeof fail);
        }
    AhoCorasick()
        {
            init();
        }
    void ins(char s[],int n)
        {
            int u=0;
            for(int i=0;i q;
            for(int i=0;i

玄武密码

  • 题意:给若干模式串和一个文本串.求每个模式串在文本串上能匹配的最大前缀长度.
  • 将模式串建成一个 \(AC\) 自动机,匹配文本串的时候往前暴力跳,跳到第一个合法的位置即可.
View code

#include"bits/stdc++.h"
using namespace std;
typedef long long LoveLive;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>‘9‘||jp<‘0‘)&&jp!=‘-‘)
        jp=getchar();
    if (jp==‘-‘)
        {
            fh=-1;
            jp=getchar();
        }
    while (jp>=‘0‘&&jp<=‘9‘)
        {
            out=out*10+jp-‘0‘;
            jp=getchar();
        }
    return out*fh;
}
const int MAXN=1e7+10;
const int Siz=4;
int n,m;
int len[MAXN];
struct AhoCorasick{
    int idx;
    inline int id(char x)
        {
            if(x==‘E‘)
                return 0;
            if(x==‘W‘)
                return 1;
            if(x==‘N‘)
                return 2;
            return 3;
        }
    int ch[MAXN][Siz];
    int fail[MAXN];
    int marked[MAXN];
    int f[MAXN];
    int val[MAXN];
    AhoCorasick()
        {
            idx=0;
            memset(fail,0,sizeof fail);
            memset(ch,0,sizeof ch);
            memset(marked,0,sizeof marked);
            memset(val,0,sizeof val);
        }
    void ins(char s[],int v)
        {
            int u=0;
            for(int i=0;i q;
            for(int i=0;i

Censoring

  • 题意:给若干模式串和一个文本串.每次从文本串开头找到一个模式串,将其删去,直到无法删去为止,求出最后剩余的文本.保证任一个模式串中没有其他模式串.
  • 将模式串建成一个 \(AC\) 自动机,用一个栈来维护当前剩余的字符.匹配成功时直接修改栈顶.同时需要维护每个节点在 \(Trie\) 树上的位置.这样删除后可以立即得出当前的位置 \(u\) .
View code

#include"bits/stdc++.h"
using namespace std;
typedef long long LoveLive;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>‘9‘||jp<‘0‘)&&jp!=‘-‘)
        jp=getchar();
    if (jp==‘-‘)
        {
            fh=-1;
            jp=getchar();
        }
    while (jp>=‘0‘&&jp<=‘9‘)
        {
            out=out*10+jp-‘0‘;
            jp=getchar();
        }
    return out*fh;
}
const int MAXN=1e5+10;
const int Siz=26;
int len[MAXN];
struct AhoCorasick{
    int idx;
    int ch[MAXN][Siz];
    int fail[MAXN];
    int val[MAXN];
    AhoCorasick()
        {
            idx=0;
            memset(ch,0,sizeof ch);
            memset(fail,0,sizeof fail);
            memset(val,0,sizeof val);
        }
    void ins(char *s,int n,int v)
        {
            int u=0;
            for(int i=0;i q;
            for(int i=0;i

单词

  • 题意:给出一个由若干单词组成的单词表,问每个单词在这个表中出现了几次.
  • 很像一个 \(kmp\) 或是 \(AC\) 自动机裸题,然而并没有那么简单.用自动机做 \(n\) 次匹配,可能会被卡掉.如果一直跳 \(fail\) 指针,就可以构造一组数据让你一直跳.
  • 正确的做法是使用 \(fail\) 树,连出这样所有的有向边 \(fail[x]->x\) .自动机上,每个节点都代表了一个前缀,连出边后,可以发现父亲节点是儿子节点的后缀.
  • 而一个字符串被匹配的次数恰好等于以它为后缀的前缀数目,即 \(fail\) 树中子树的大小.
  • 插入字符串的时候将经过的每个节点的权值 \(+1\) ,最后 \(dfs\) 统计即可.
View code

#include"bits/stdc++.h"
using namespace std;
typedef long long LoveLive;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>‘9‘||jp<‘0‘)&&jp!=‘-‘)
        jp=getchar();
    if (jp==‘-‘)
        {
            fh=-1;
            jp=getchar();
        }
    while (jp>=‘0‘&&jp<=‘9‘)
        {
            out=out*10+jp-‘0‘;
            jp=getchar();
        }
    return out*fh;
}
const int MAXN=1e6+10;
const int Siz=26;
int n;
struct AhoCorasick{
    int idx;
    int ch[MAXN][Siz];
    int fail[MAXN];
    int pos[MAXN];
    int val[MAXN];
    int ecnt;
    int head[MAXN],to[MAXN],nx[MAXN],siz[MAXN];
    AhoCorasick()
        {
            idx=0;
            ecnt=0;
            memset(ch,0,sizeof ch);
            memset(fail,0,sizeof fail);
            memset(val,0,sizeof val);
            memset(head,0,sizeof head);
        }
    void ins(char *s,int len,int v)
        {
            int u=0;
            for(int i=0;i q;
            for(int i=0;i

病毒

  • 题意:给出若干个 \(01\) 串,问是否存在一个无限长的 \(01\) 串,满足所有给出的串都不是它的子串.
  • 将给出的串插入到 \(AC\) 自动机里,那么若存在一个环,环上的节点及它们沿 \(fail\) 指针向上跳都不经过单词末节点,则符合要求.
  • 插入的时候将权值一起合并,最后做一次 \(dfs\) 即可.
View code

#include"bits/stdc++.h"
using namespace std;
typedef long long LoveLive;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>‘9‘||jp<‘0‘)&&jp!=‘-‘)
        jp=getchar();
    if (jp==‘-‘)
        {
            fh=-1;
            jp=getchar();
        }
    while (jp>=‘0‘&&jp<=‘9‘)
        {
            out=out*10+jp-‘0‘;
            jp=getchar();
        }
    return out*fh;
}
const int MAXN=3e4+10;
const int Siz=2;
struct AhoCorasick{
    int idx;
    int ch[MAXN][Siz];
    int fail[MAXN];
    int val[MAXN];
    AhoCorasick()
        {
            idx=0;
            memset(ch,0,sizeof ch);
            memset(val,0,sizeof val);
            memset(fail,0,sizeof fail);
        }
    void ins(char *s,int len)
        {
            int u=0;
            for(int i=0;i q;
            for(int i=0;i

文本生成器

  • 题意:给出若干个由大写字母构成的单词,问长度为 \(m\) ,由大写字母构成的字符串中,包含至少一个单词的数目.对 \(10007\) 取模.
  • 可以先求出不包含任意一个单词的字符串数目,再用总数目\(26^m\)减去.
  • 将单词建成一个 \(AC\) 自动机,类似上题,合并权值即可求出一个节点是否能被走到.
  • \(f[i][j]\) 表示已经走了 \(i\) 步,走到了节点 \(j\) 时的方案数. \(O(n^2)\ dp\) 即可.
View code

#include"bits/stdc++.h"
using namespace std;
typedef long long LoveLive;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>‘9‘||jp<‘0‘)&&jp!=‘-‘)
        jp=getchar();
    if (jp==‘-‘)
        {
            fh=-1;
            jp=getchar();
        }
    while (jp>=‘0‘&&jp<=‘9‘)
        {
            out=out*10+jp-‘0‘;
            jp=getchar();
        }
    return out*fh;
}
const int P=1e4+7;
inline int add(int a,int b)
{
    return (a+b) % P;
}
inline int mul(int a,int b)
{
    return a * b % P;
}
int fpow(int a,int b)
{
    int res=1;
    while(b)
        {
            if(b&1)
                res=mul(a,res);
            a=mul(a,a);
            b>>=1;
        }
    return res;
}
const int MAXN=7777;
const int Siz=26;
int n,m;
struct AhoCorasick{
    int idx;
    int ch[MAXN][Siz];
    int fail[MAXN];
    int val[MAXN];
    int f[101][MAXN];
    AhoCorasick()
        {
            idx=0;
            memset(ch,0,sizeof ch);
            memset(fail,0,sizeof fail);
            memset(val,0,sizeof val);
            memset(f,-1,sizeof f);
        }
    void ins(char *s,int len)
        {
            int u=0;
            for(int i=0;i q;
            for(int i=0;i

小结

  • \(AC\) 自动机可以解决一部分多模式串有关问题.其附带品 \(fail\) 树也有不错的性质.

AC自动机学习小结

标签:小结   tps   return   break   read   pos   讲解   struct   大写   

原文地址:https://www.cnblogs.com/jklover/p/10251543.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!