首页 > 其他分享 >AC 自动机学习笔记

AC 自动机学习笔记

时间:2024-08-09 21:49:27浏览次数:8  
标签:AC int 笔记 提交 fail 自动机 dp

1.KMP 自动机

1.1 内容

KMP 自动机本质上就是单串的 AC 自动机。

我们定义转移函数为:

\[\delta(i, c) = \begin{cases} \delta(\pi_i, c)&s_{i+1} \not= c\\ i + 1&s_{i+1} = c \end{cases} \]

其实也就是模拟了 KMP 的整个过程。

1.2 应用

自动机上跑 dp 是最常见的应用,一般会有一维是自动机的状态。

对于一些问题还可以用矩阵优化。

CF808G Anthem of Berland

设 \(dp(i,j)\) 表示确定了前 \(i\) 个字符,当前在 \(j\) 状态,最多匹配了几次。转移就是简单的线性 dp。

提交记录

P3193 [HNOI2008] GT考试

设 \(dp(i,j)\) 表示确定了前 \(i\) 个字符,当前在 \(j\) 状态的方案数。转移用矩阵快速幂优化。

提交记录

P3082 [USACO13MAR] Necklace G

设 \(dp(i,j)\) 表示前 \(i\) 个确定,在 \(j\) 状态,最多保留几个。

提交记录

2. AC 自动机

2.1 内容

假设现在我们是一个多串匹配的问题,我们该如何建立自动机。

首先,我们需要将所有串建成一颗 Trie,然后我们定义转移函数:

\[\delta(i, c) = \begin{cases} child[i][c]&child[i][c] \text{ exist}\\ \delta(fail_i, c)&\text{Otherwise.} \end{cases} \]

其中的 fail 称作失陪指针,和单串中的 \(\pi\) 是类似的,指向最长的真后缀。

但是 AC 自动机其实有两个和重要的东西:转移表和 fail 树,转移表就是上面的东西,而 fail 树指的是每个点向 fail 连边形成的树。这个在解决问题时帮助很大。

我们考虑 5357 【模板】AC 自动机 的问题:

给定 \(S\) 和 \(t_1 \sim t_n\),求每个 \(t_i\) 在 \(S\) 中出现次数。

我们对 \(t\) 建出 AC 自动机,然后我们跑一边 \(S\),将其经过的所有点都打上标记。

我们观察 fail 树会发现每个串出现当且仅当经过的是子树内的点。于是我们求子树和就能得出问题的答案。

建立 AC 自动机的过程可以用 bfs 来建,同时由于我们遍历的顺序是字典序,所以我们可以把队列保留下来,求子树和时倒序求即可。

给出代码:

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2e5 + 5;
const int S = 26;
const int M = 2e6 + 5;

int n;
int ch[N][S] = {{0}}, fail[N] = {0}, cnt;
int ed[N] = {0}; // ed[i]: 第 i 个模式串的节点
int f[N] = {0}; // f[i]: 节点 i 的经过次数 ==> 子树 i 的经过次数
int q[N] = {0}, fr, ba;
char s[M];

void insert(int x) {//第 x 个模式串
	int now = 0;
	for (int i = 0; s[i]; i++) {
		if (!ch[now][s[i] - 'a'])
			ch[now][s[i] - 'a'] = ++cnt;
		now = ch[now][s[i] - 'a'];
	}
	ed[x] = now;
}


void getfail() {
	fr = 1, ba = 0;
	for (int i = 0; i < S; i++)
		if (ch[0][i])
			q[++ba] = ch[0][i];
	while (fr <= ba) {
		int x = q[fr++];
		for (int i = 0; i < S; i++)
			if (!ch[x][i])
				ch[x][i] = ch[fail[x]][i];
			else {
				fail[ch[x][i]] = ch[fail[x]][i];
				q[++ba] = ch[x][i];
			}
	}
}

void run() {
	int now = 0;
	for (int i = 0; s[i]; i++) {
		now = ch[now][s[i] - 'a'];
		++f[now];
	}
}


int main() {
	cnt = 0;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%s", s);
		insert(i);
	}
	getfail();
	scanf("%s", s);
	run();
	for (int i = cnt; i >= 1; i--)
		f[fail[q[i]]] += f[q[i]];
	for (int i = 1; i <= n; i++)
		printf("%d\n", f[ed[i]]);
	return 0;
}

2.1 应用

AC 自动机可以配合 dp,数据结构等解决复杂问题。

P6257 [ICPC2019 WF] First of Her Name

首先自然是把名字反过来,然后就可以建出 AC 自动机,现在我们把查询也反过来,变成查询拥有给定后缀的字符串个数。

由于是后缀,所以我们考虑把询问串也丢到 AC 自动机中,这样所有以这个串为后缀的字符串都在其 fail 树的子树中!求子树和即可。

提交记录

CF856B Similar Words

转化一下题意:两个串不能同时当选当且仅当相等或者 \(A\) 去掉第一个字符是 \(B\)。

我们发现这个限制意味着 \(B\) 是 \(A\) 的 fail 指向的点,建出 fail 树后转化成一些边的两端不能同时选,树上最大独立集!

直接 \(dp\) 即可。

提交记录

P2444 [POI2000] 病毒

经典题目。

我们考虑建出 AC 自动机,显然如果是无限长那么一定存在循环节,这意味着我们能在 AC 自动机上找到一个环并且没有经过任何不该去的节点。

我们发现,如果一个点在 Trie 上的祖先有单词,或者 fail 树上的祖先有单词就不能去,否掉这些点,然后拓扑排序判环即可。

提交记录

CF696D Legen...

在 AC 自动机上跑 dp,矩阵优化。

提交记录

P5231 [JSOI2012] 玄武密码

求 fail 子树和,然后直接统计即可。

提交记录

P3121 [USACO15FEB] Censoring G

找到就删,维护一个栈记录所有当问过的状态方便一步跳回。

提交记录

P3041 [USACO12JAN] Video Game G

自动机上跑 dp,\(dp(i,j)\) 前 \(i\) 个在 \(j\) 的最多得分。其实数据范围可以开大然后矩阵优化。

提交记录

P4052 [JSOI2007] 文本生成器

也是 dp,需要多记一维表示是否已经到达过终止状态。

提交记录

P2414 [NOI2011] 阿狸的打字机

超级无敌经典题,而且其实出的很好。

首先我们对于所有串建出 AC 自动机。我们观察如果 \(x\) 在 \(y\) 中出现意味着什么。

意味着从 Trie 上 \(y\) 路径上的点的 fail 树上的祖先有 \(x\),所以我们可以转化成一条从根出发的路径上有多少在 dfn 序的某个区间内。

这个问题可以离线然后用 BIT 和一遍 dfs 搞定。

提交记录

CF163E e-Government

我们考虑先建出 AC 自动机,然后对于每次修改直接修改一个点的子树的所有权值,然后询问就是跑一遍,每次询问单点。

用 BIT 和 dfs 序维护即可。

标签:AC,int,笔记,提交,fail,自动机,dp
From: https://www.cnblogs.com/rlc202204/p/18351570

相关文章

  • Datawhale AI夏令营第四期 魔搭-AIGC方向 task01笔记
    DatawhaleAI夏令营第四期魔搭-AIGC方向task01笔记提示词提示词很重要,一般写法:主体描述,细节描述,修饰词,艺术风格,艺术家举个例子【promts】Beautifulandcutegirl,smiling,16yearsold,denimjacket,gradientbackground,softcolors,softlighting,cinematicedge......
  • [论文阅读]Mobility-Aware Cooperative Caching in VEC Based on CAFR
    论文:Mobility-AwareCooperativeCachinginVehicularEdgeComputingBasedonAsynchronousFederatedandDRLJSTSP2022基于异步联邦和深度强化学习的车载边缘计算移动感知协同缓存一、Introductionbackground:随着车联网(IoV)和云计算(CloudComputing)的发展,缓存技术......
  • Adobe Premiere Pro PR2024中文版win/mac软件安装下载
    一、简介AdobePremierePro2024(简称PR2024)是Adobe公司推出的一款专业视频编辑软件,广泛应用于电影、电视、网络视频制作等领域。作为AdobeCreativeSuite的一部分,PR2024继承了Adobe家族一贯的简洁界面和强大功能,同时结合了最新的技术和用户需求,为用户提供了更加高效、直观......
  • System to practice
    1、Linux中哪个系统调用可以用于设置一个定时器,当时间到时,发送一个信号给进程?(B)a)setitimer()b)alarm()c)timer_create()d)time()tips:timer_create()是一个用于创建定时器的系统调用函数,定义在POSIX标准中,属于Linux系统的时间管理功能。它用于创建一个定时器对象,并......
  • CF641E Little Artem and Time Machine 题解
    题目传送门前置知识CDQ分治解法单点修改区间查询,但值域巨大,考虑离散化掉\(x\)。时刻\(t\)仍很大,考虑将其作为CDQ分治的第一维,然后套个CDQ分治即可,注意及时清空桶数组。代码CodeForces275382150#include<bits/stdc++.h>usingnamespacestd;#definelllonglon......
  • XetHub 加入 Hugging Face!
    我们非常激动地正式宣布,HuggingFace已收购XetHub......
  • 基于 SeetaFace6 的 .NET 人脸识别解决方案
    ViewFaceCore/ViewFaceCore1.关于一个基于SeetaFace6的.NET人脸识别解决方案本项目受到了SeetaFaceEngine.Net的启发开源、免费、跨平台(win/linux)2.快速开始2.1受支持的.NET框架和操作系统目标框架最低版本操作系统.NETFramework4.0win(......
  • Character包装类
    packagecom.shujia.day12;/*Character:是基本数据类型char的包装类成员方法:publicstaticbooleanisUpperCase(charch)判断是否为大写publicstaticbooleanisLowerCase(charch)判断是否为小写publicstaticbooleanisDigit(cha......
  • java基础学习笔记1
    Java编程规范命名风格1.【强制】代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。反例:_name/__name/$name/name_/name$/name__2.【强制】代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。说明:正确的英文拼写......
  • Oracle数据库巡检
    数据库巡检列表序号业务系统1主机名2操作系统4单机/RAC4IP地址5地址类型6数据类型7数据库版本8实例名巡检方案检查方面具体检查内容检查标准集群配置集群软件版本集群软件版本要等于或高于DB软件版本集群服务状态各种服务状态(除GSD外)需是ONLINE注:使用asfforrac的环境下......