「学习笔记」AC自动机

摘要:
我还记得2019年夏天,gy在英雷华打开了ybt改进章节的目录概览。一般来说,KMP算法用于处理单模式字符串匹配问题。如果我们想处理多模式字符串的问题,我们需要引入AC自动机。AC自动机基于Trie的结构并结合KMP的思想。标记的不匹配指针,即的最长后缀。如果存在,可以通过添加字符来获得。否则,它将直接指向状态void build(){forifq.push;而{intu=q.front();q.pop();for{if{fail[tr[u][i]]=tr[fail[u]][i];q.prush;}elstr[u][i]=tr[fail[u]][i];}}匹配函数以P3808AC自动机(简单版本)的要求为例,int query{int u=0,res=0;for{u=tr〔u〕〔t〔i〕-‘a’〕;for(int j=u;j&&e〔j〕!=-1;j=fail〔j〕){res+=e〔j},e〔j】=-1;}}return;}板P5357AC自动机#包含 使用namespacestd;组成N=2e5+5;头[N],至[N],ne[N],tot;intn,tr[N][26],fail[N],ch,book[N],sz[N];字符[N*10];队列<int>q;voidbuild(){forifq.push;而{intu=q.front();q.pop();for{if{fail[tr[u][i]]=tr[fail[u]][i];q.ppush;}elsetr[u][i]=tr[fail[u]][i];}}}inlinevoidadd{to[++tot]=v;ne[tot]=head[u];head[u]=tot;}voiddfs{for{intv=to[i];dfs;sz[u]+=sz[v];}}intmain(){scanf;for{scanf;intu=0;for{if(!

还记得2019年暑假,gy在英乐华翻开ybt提高篇的目录

概述

通常来讲,KMP 算法用来处理单模式串匹配问题。而若要处理多模式串的问题,就要引出 AC自动机

AC自动机 是以 Trie 的结构为基础,结合 KMP 的思想建立的。

步骤

  1. 将所有模式串构建成一棵 Trie

  2. Trie 上所有节点构造失配指针(最长后缀)

  3. 利用失配指针对主串进行匹配。

流程

  • 构建指针

    (tr[p][c]=v) 表示结点 (v) 的父结点 (p) 通过字符 (c) 指向 (v)

    (fail[u]) 表示 (u) 的失配指针,即 (u) 的最长后缀。

    1. (tr[u][i]) 存在,则 (fail[tr[u][i]]) 可以由 (fail[u]) 增加一个字符 (i) 得到

    2. 否则,直接将 (tr[u][i]) 指向 (tr[fail[u]][i]) 的状态

    void build(){
        for(int i=0;i<26;i++)
            if(tr[0][i])q.push(tr[0][i]);
        while(q.size()){
            int u=q.front();
            q.pop();
            for(int i=0;i<26;i++){
                if(tr[u][i]){
                    fail[tr[u][i]]=tr[fail[u]][i];
                    q.push(tr[u][i]);
                }
                else tr[u][i]=tr[fail[u]][i];
            }
        }
    }
    
  • 匹配函数

    P3808 【模板】AC自动机(简单版)的要求为例

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

板子

P5357 【模板】AC自动机(二次加强版)

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

const int N=2e5+5;
int head[N],to[N],ne[N],tot;
int n,tr[N][26],fail[N],ch,book[N],sz[N];
char s[N*10];
queue<int> q;

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

inline void add(int u,int v){
	to[++tot]=v;
	ne[tot]=head[u];
	head[u]=tot;
}

void dfs(int u){
	for(int i=head[u];i;i=ne[i]){
		int v=to[i];
		dfs(v);
		sz[u]+=sz[v];
	}
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		int u=0;
		for(int j=1;s[j];j++){
			if(!tr[u][s[j]-'a'])tr[u][s[j]-'a']=++ch;
			u=tr[u][s[j]-'a'];
		}
		book[i]=u;
	}
	build();
	scanf("%s",s+1);
	for(int u=0,i=1;s[i];i++){
		u=tr[u][s[i]-'a'];
		sz[u]++;
	}
	for(int i=1;i<=ch;i++){
		add(fail[i],i);
	}
	dfs(0);
	for(int i=1;i<=n;i++)printf("%d
",sz[book[i]]);
	return 0;
}

免责声明:文章转载自《「学习笔记」AC自动机》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇ios 给UIView添加背景图片APICloud上啦加载下拉刷新模块下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

字符串匹配算法

一、简介 文本信息可以说是迄今为止最主要的一种信息交换手段,而作为文本处理中的一个重要领域——字符串匹配,就是我们今天要说的话题。(原文还特意提及文本数据数量每18个月翻一番,以此论证算法必须要是高效的。不过我注意到摩尔定律也是18个月翻番,这正说明数据的增长是紧紧跟随处理速度的,因此越是使用高效的算法,将来待处理的数据就会越多。这也提示屏幕前的各位,代码...

后缀自动机构建图解

目录 后缀自动机构建图解 case1 case2 case3 后缀自动机构建图解 我是在这学的:https://www.luogu.com.cn/blog/Kesdiael3/hou-zhui-zi-dong-ji-yang-xie 感觉作者画的图有点难理解,而且讲到了所以来画一画,方便复习。看本文前最好先把上面那个看一遍! 此处是从右往左增量,...

回文自动机做题小结

模板 求以每个位置结尾的回文串的数量,加密输入 就是回文自动机节点的(len)数组,对应的是最长回文后缀 双倍回文 求形如(AA^rAA^r) 方法一:建立(fail)树,然后对每个(len)是偶数的点,在子树内找有没有长度为(2*len)的点,通过打标记做到(O(n)) 方法二:求一个与(fail)数组对应的(tran)数组,含义为长度不超过(frac{...

「专题总结」后缀自动机

后缀自动机重点在于性质,东西很多注意区分概念。 后缀自动机是一个(DAG),从根开始的路径能够识别(S)的每个后缀(子串),一定不存在一条从根开始的路径能够识别不是S的子串。 点:每个节点代表了一个(endpos)类,从根到该节点的所有字符串在S中的出现位置相同,一个点代表的(endpos)集相同的各个串之间有后缀关系且连续,暂且称这些串的集合为(P)。...