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的时候会出锅! 题意: 求一个字符串中本质不同的连续子串有几个,但是某串和它反转后的字符串算一个. 题解: 要注意的是,一般字符串题中的“ ...
随机推荐
- windows 安装配置mysql 8,以及远程连接访问
官网下载mysql8,https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.11-winx64.zip 1.解压zip包到安装目录 比如我的安 ...
- 【2020NOI.AC省选模拟#5】C. 光滑序列
题目链接 原题解: 光滑的序列一定有长度为$K$的循环节. 使用动态规划,设$F(i,j)$为使前$i$个整数的和为$j$的最小修改次数. 记$cost(i,v)$为令$A_i,A_{i+K},A_{ ...
- mysql的日期输出格式列出来
mysql的日期输出格式列出来: %a 缩写星期名 %b 缩写月名 %c 月,数值 %D 带有英文前缀的月中的天 %d 月的天,数值(00-31) %e 月的天,数值(0-31) %f 微秒 %H 小 ...
- ZSTUOJ刷题④:Problem B.--输出双层金字塔
Problem B: 输出双层金字塔 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 7860 Solved: 5834 Description 输出双层 ...
- 19 request请求数据大全
1 request.path_info # 获取当前用户请求的url # http://127.0.0.1:8000/customer/list/ ----> /customer/list/ # ...
- mangodb查询语句
1.查询所有记录 db.userInfo.find(); 相当于: select* from userInfo; 默认每页显示20条记录,当显示不下的情况下,可以用it迭代命令查询下一页数据.注意:键 ...
- Python pdb模块的使用
野路子出生,写Python也有段时间了,一般的调试都用的print, PyCharm的debug功能也用的比较少,主要一般也用不到,第二是自己也不怎么会用. 服务器开发,本地根本没有运行的环境,前面学 ...
- html input 属性
一:disabled disabled 属性规定应该禁用 input 元素,被禁用的 input 元素,不可编辑,不可复制,不可选择,不能接收焦点,后台也不会接收到传值.设置后文字的颜色会变成灰色.d ...
- Liunx mosquitto卸载
1.查询文件: whereis mosquitto whereis mosquitto_sub 2.删除查询到的文件,命令: rm -rf /etc/mosquitto rm -f /usr/loca ...
- 关于git错误:Git未能顺利结束(退出码 128)的解决办法
如图: 问题原因: 主要是:用户名.邮箱.用户密钥跟github官网上配置的不一致 https://blog.csdn.net/weixin_52517585/article/details/1269 ...