KMP 自动机,孤独的自动机(同时也是CF1721E的题解)
给定字符串 \(s\),以及 \(q\) 个串 \(t_i\),求将 \(s\) 分别与每个 \(t_i\) 拼接起来后,最靠右的 \(|t_i|\) 个前缀的 border 长度。询问间相互独立。
\(|s|\leq 10^6, q \leq 10^5, |t_i|\leq 10\) 。
(题面来自洛谷)
看到 border ,第一反应就是 KMP 。又想到 KMP 的 next 数组就是干这件事的,于是就有了一个很逊的想法:每次当做 \(t\) 真的接到了 \(s\) 的后面,对 \(t\) 的字符做 KMP 。看起来复杂度很对,但由于要往回跳,不出七个测试点就会超时。
思考一下,如果跳到了 s 以内的字符,那么实际上跳到哪里是固定的。由于我们只需要对 t 中字符匹配,所以完全可以只存储跳到 s 中每个字符时最终会跳到哪里。
发现 AC 自动机就是干这件事的,于是我们可以对单个字符串建立 AC 自动机。无聊的人类将单个串的 AC 自动机叫做 KMP 自动机。
很棒的一点是由于 AC 自动机单个字符的构建是 \(O(1)\) 的,所以我们可以直接按照上面的很逊的方式构建 AC 自动机。预处理复杂度为 \(O(|S|)\) ,单词询问复杂度为\(O(|T|)\)。
这个优化的本质是将 KMP 中往回跳的路径用 AC 自动机的构造方式进行压缩。
要处理的地方是 \(s\) 与 \(t\) 的交界处。 \(s\) 的最后一个字符的儿子要进行更改,过后也要记得还原。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn =(1 << 20) + 5;
int qian[maxn];
int ch[maxn][26], col[maxn], tot;
int fail[maxn];
void add(string s)
{
int n = s.size(), u = 0;
for(int i = 1;i < n;i ++)
{
int p = s[i] - 'a';
if(!ch[u][p]) ch[u][p] = ++ tot;
u = ch[u][p];
}
col[u] ++;
}
void build()
{
queue<int> q;
for(int i = 0;i < 26;i ++) if(ch[0][i]) q.push(ch[0][i]);
while(!q.empty())
{
int u = q.front();
q.pop();
for(int i = 0;i < 26;i ++)
{
if(!ch[u][i]) ch[u][i] = ch[fail[u]][i];
else fail[ch[u][i]] = ch[fail[u]][i],q.push(ch[u][i]);
}
}
}
int yuan[27];
int main(){
freopen("text.in", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
string s;
cin >> s;
int n = s.size();
s = ' ' + s;
add(s);
build();
int Q;
cin >> Q;
while(Q --)
{
string t;
cin >> t;
int m = t.size();
t = ' ' + t;
int j = ch[n - 1][s[n] - 'a'];
int p = tot;
for(int i = 0;i < 26;i ++) yuan[i] = ch[tot][i];
for(int i = 1;i <= m;i ++)
{
j = ch[j][t[i] - 'a'];
ch[tot][t[i] - 'a'] = tot + 1;
fail[tot + 1] = ch[fail[tot]][t[i] - 'a'];
cout << j << ' ';
tot ++;
for(int i = 0;i < 26;i ++) ch[tot][i] = ch[fail[tot]][i];
}
for(int i = 0;i < 26;i ++) ch[p][i] = yuan[i];
for(int i = p + 1;i <= tot + 1;i ++)
{
for(int j = 0;j < 26;j ++) ch[i][j] = 0;
if(i != p) fail[i] = 0;
}
tot = p;
cout << endl;
}
return 0;
}
KMP 自动机,孤独的自动机(同时也是CF1721E的题解)的更多相关文章
- 【Luogu3804】【模板】后缀自动机(后缀自动机)
[Luogu3804][模板]后缀自动机(后缀自动机) 题面 洛谷 题解 一个串的出现次数等于\(right/endpos\)集合的大小 而这个集合的大小等于所有\(parent\)树上儿子的大小 这 ...
- 【BZOJ4032】[HEOI2015]最短不公共子串(后缀自动机,序列自动机)
[BZOJ4032][HEOI2015]最短不公共子串(后缀自动机,序列自动机) 题面 BZOJ 洛谷 题解 数据范围很小,直接暴力构建后缀自动机和序列自动机,然后直接在两个自动机上进行\(bfs\) ...
- 模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合)
模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合) Code: #include <bits/stdc++.h> using namespace std; #define ...
- KMP,HASH,Trie,AC自动机
我做个总结算了下午看了一下AC自动机和学习我的大生物(当然是多谢鑫神了)..完了要崩.. 1 KMP 只要是学过的人都觉得比较简单吧 但是学不会的人就感觉很难了,我是那种顿悟的然后感觉非常简单的人过程 ...
- Aho_Corasick自动机(AC自动机)
首先,AC自动机不是Accept自动机,别以为把这段代码复制到OJ上就全都自动AC了…… 其实这玩意是Aho-Corasick 造出来的,所以你懂的. 那么这玩意能干嘛咧? •字符串的匹配问题 •多串 ...
- 后缀自动机&回文自动机学习笔记
在学了一天其实是边学边摆之后我终于大概$get$后缀自动机了,,,就很感动,于是时隔多年我终于决定再写篇学习笔记辽$QwQ$ $umm$和$FFT$学习笔记一样,这是一篇单纯的$gql$的知识总结博, ...
- 后缀自动机/回文自动机/AC自动机/序列自动机----各种自动机(自冻鸡) 题目泛做
题目1 BZOJ 3676 APIO2014 回文串 算法讨论: cnt表示回文自动机上每个结点回文串出现的次数.这是回文自动机的定义考查题. #include <cstdlib> #in ...
- 【AC自动机】AC自动机
Definition & Solution AC自动机是一种多模式串的字符串匹配数据结构,核心在于利用 fail 指针在失配时将节点跳转到当前节点代表字符串的最长后缀子串. 首先对 模式串 建 ...
- D. Match & Catch 后缀自动机 || 广义后缀自动机
http://codeforces.com/contest/427/problem/D 题目是找出两个串的最短公共子串,并且在两个串中出现的次数只能是1次. 正解好像是dp啥的,但是用sam可以方便很 ...
- 牛客多校第四场 I string 后缀自动机/回文自动机
这个回文自动机的板有问题,它虽然能过这道题,但是在计算size的时候会出锅! 题意: 求一个字符串中本质不同的连续子串有几个,但是某串和它反转后的字符串算一个. 题解: 要注意的是,一般字符串题中的“ ...
随机推荐
- 华为光猫HG8346V5配置
- Kubernetes--Ingress资源类型
Ingress资源类型 基于HTTP暴露的每个Service资源均可发布于一个独立的FQDN主机名之上,如 " www.ik8s.io " :也可发布于某主机上的URL路径之上,从 ...
- Docker学习——Docker 三剑客(七)
Docker Compose 简介 Docker Compose 是 Docker 官方编排(Orchestration)项目之一,负责arg>...] [options] [COMMAND] ...
- Linux系统安装&VMware安装三
第十四步: 开始安装
- javascript向tabale中动态添加数据
<table width="600" border="1" cellspacing="0"> <thead> < ...
- XSS跨站脚本攻击(Cross Site Scripting)
XSS是跨站脚本攻击(Cross Site Scripting),不写为CSS是为了避免和层叠样式表(Cascading Style Sheets)的缩写混淆,所以将跨站脚本攻击写为XSS. 攻击者可 ...
- oracle建表和sqlserver建表
oracle declare num number;begin select count(1) into num from user_all_tables where Upper(Table_Name ...
- Windows+svn +Jenkins+发布NetCore/VUE项目
1. NetCore环境下载,注意是下载SDK,不是Runtime:https://dotnet.microsoft.com/download/dotnet-core?utm_source=getdo ...
- Vue-数据代理
Vue中的数据代理 数据代理定义 所谓数据代理,就是通过一个对象代理对另一个对象中的属性的操作(读/写).说白了就是操作一个对象上的属性可以读取和修改另一个对象上的属性,这种关系就叫做数据代理. 在V ...
- C的基础常识
C是可移植性语言,因此可以在许多环境中使用,包括UNIX.Linux.MS-DOS.Windows和Macintosh OS. 使用C语言编写的内容的文本,称为源代码文件(source code fi ...