[BZOJ 1535] [Luogu 3426]SZA-Template (KMP+fail树+双向链表)
[BZOJ 1535] [Luogu 3426]SZA-Template (KMP+fail树+双向链表)
题面
Byteasar 想在墙上涂一段很长的字符,他为了做这件事从字符的前面一段中截取了一段作为模版. 然后将模版重复喷涂到相应的位置后就得到了他想要的字符序列.一个字符可以被喷涂很多次,但是一个位置不能喷涂不同的字符.做一个模版很费工夫,所以他想要模版的长度尽量小,求最小长度是多少.
拿样例来说ababbababbabababbabababbababbaba , 模版为前8个字符ababbaba, 喷涂的过程为: ababbababbabababbabababbababbaba
分析
分析模板串,我们会发现3条性质
模板串性质:
- 一个模板串A是要求的文本串B的公共前后缀
- 如果一个模板串A有另一个模板串B(也就是B可以覆盖A),那么B是比A更优的一个解
- 如果模板串A可以完全覆盖文本串B,那么A在B中的匹配位置(按照开头算)之间的空格数不会超过A的长度
证明:
1.如果不是前后缀的话,那开头和结尾就没法涂了
2.由模板串的定义显然
3.画个图或者看样例,喷涂的时候模板串必须相邻或重叠
由性质1,我们发现满足条件的模板串一定是1~next[n],或next[next[n]],next[next[next[n]]]...这样的子串。
因此我们可以枚举前缀的长度,然后\(O(n)\)判定,但这样的复杂度仍是\(O(n^2)\)的,考虑优化
这时就需要用到fail树。
fail树其实就是把失配的位置连起来得到的一棵树。我们对于\(i \in [1,n]\),连边\((next[i],i)\),\(next[i]\)为\(i\)的父亲。由于\(next[i]<i\),连出来的一定是一棵树
显然fail树的根为0,fail树上的节点x表示文本串中1x位,长度为x的子串。而1next[n],或next[next[n]],next[next[next[n]]]...这样的子串其实就是fail树上0~next[n]的一条链。
fail树的性质:
y代表的子串的一个公共前后缀为x代表的子串,当且仅当点x是点y的祖先
因此我们就可以先把0next[n]的链上的节点标记,从根对fail树dfs。每次选在链上的儿子节点递归,然后删除其他儿子节点子树里的所有节点。用一个初始时为1n的链的双向链表维护相邻元素之间的距离(初始距离为1,删掉x,y中间的一个节点z,x,y之间的距离变为dist(x,z)+dist(y,z))。
容易发现这个距离就是模板串在文本串中的匹配位置之间的空格数.根据模板串的性质3,空格数不会超过模板串的长度。而节点x又表示长度为x的子串,因此递归到$x \geq 空格数 $的时候,x就是最小长度.
由于每个节点最多被删除一次,时间复杂度\(O(n)\)
广告:
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define maxn 500000
using namespace std;
struct edge{
int from;
int to;
int next;
}E[maxn*2+5];
int sz=1;
int head[maxn+5];
void add_edge(int u,int v){
sz++;
E[sz].from=u;
E[sz].to=v;
E[sz].next=head[u];
head[u]=sz;
}
int n;
char s[maxn+5];
int nex[maxn+5];
struct list{
int pre[maxn+5],nex[maxn+5];
int mv;
void ini(int n){
mv=1;
for(int i=1;i<=n;i++){
pre[i]=i-1;
nex[i]=i+1;
}
}
void del(int x){
pre[nex[x]]=pre[x];
nex[pre[x]]=nex[x];
mv=max(mv,nex[x]-pre[x]);
pre[x]=nex[x]=0;
for(int i=head[x];i;i=E[i].next){
int y=E[i].to;
del(y);
}
}
inline int query(){
return mv;
}
}S;
int ans=0;
bool mark[maxn+5];
void dfs(int x){//x实际上是某个nex,代表前缀(模板串)长度
int to;
if(S.query()<=x){//模板串性质3
ans=x;
return;
}
for(int i=head[x];i;i=E[i].next){
int y=E[i].to;
if(mark[y]) to=y;
else S.del(y);//根据fail树的性质2,把不能匹配的部分去掉,得到两个匹配位置之间的最大距离
}
dfs(to);
}
int main(){
scanf("%s",s+1);
n=strlen(s+1);
for(int i=2,j=0;i<=n;i++){
while(j>0&&s[j+1]!=s[i]) j=nex[j];
if(s[j+1]==s[i]) j++;
nex[i]=j;
}
for(int i=1;i<=n;i++) add_edge(nex[i],i);//建立fail树
S.ini(n);
for(int i=n;i>0;i=nex[i]) mark[i]=1;//模板串性质1
dfs(0);
printf("%d\n",ans);
}
[BZOJ 1535] [Luogu 3426]SZA-Template (KMP+fail树+双向链表)的更多相关文章
- [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)
[BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...
- bzoj 2746: [HEOI2012]旅行问题 AC自动机fail树
2746: [HEOI2012]旅行问题 Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 489 Solved: 174[Submit][Status ...
- BZOJ 2085 luogu P3502 [POI2010]Hamsters (KMP、Floyd、倍增)
数组开小毁一生-- 题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2085 这题在洛谷上有个条件是"互不包含",其实 ...
- luogu 3426题解 (KMP)
题面 Byteasar 想在墙上涂一段很长的字符,他为了做这件事从字符的前面一段中截取了一段作为模版. 然后将模版重复喷涂到相应的位置后就得到了他想要的字符序列.一个字符可以被喷涂很多次,但是一个位置 ...
- Bzoj 2286 & Luogu P2495 消耗战(LCA+虚树+欧拉序)
题面 洛谷 Bzoj 题解 很容易想到$O(nk)$的树形$dp$吧,设$f[i]$表示处理完这$i$颗子树的最小花费,同时再设一个$mi[i]$表示$i$到根节点$1$路径上的距离最小值.于是有: ...
- BZOJ 2434 阿狸的打字机(fail树)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2434 题意:阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28 ...
- BZOJ 5168 && Luogu P3740 [HAOI2014]贴海报 线段树~~
据说某谷数据十分水...但幸好BZOJ上也过了...话说我记得讲课时讲的是奇奇怪怪的离散化..但现在突然觉得什么都可以线段树瞎搞了...QAQ 直接就是这个区间有没有被覆盖,被覆盖直接return: ...
- BZOJ.1535.[POI2005]SZA-Template(KMP DP)
BZOJ 洛谷 \(Description\) 给定一个字符串\(s\),求一个最短的字符串\(t\)满足,将\(t\)拼接多次后,可以得到\(s\).拼接是指,可以将\(t\)放在当前串的任意位置, ...
- BZOJ 4044 Luogu P4762 [CERC2014]Virus Synthesis (回文自动机、DP)
好难啊..根本不会做..基本上是抄Claris... 题目链接: (bzoj)https://www.lydsy.com/JudgeOnline/problem.php?id=4044 (luogu) ...
随机推荐
- 【清华集训2016】Alice和Bob又在玩游戏
不难的题目.因为SG性质,所以只需要对一棵树求出. 然后如果发现从上往下DP不太行,所以从下往上DP. 考虑一个点对子树的合并,考虑下一个删的点在哪一个子树,那么剩下的状态实际上就是把一个子树所有能达 ...
- jQuery_获取html代码以及更改内容
代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title ...
- 智能指针之shared_ptr基本概述
1.shared_ptr允许有多个指针指向同一个对象,unique_ptr独占所指向的对象. 2.类似于vector,智能指针也是模板.创建智能指针: shared_ptr<string> ...
- latex参考文献中作者名字含有特殊字符怎么办
- JavaBean,EJB,POJO,Spring Bean 的演进历程
JavaBean Sun公司对类提出的规范:1,类是public的2,有一个无参构造方法3,属性修饰要用private,通过get set操作4,实现Serializable接口5,对事件使用Swin ...
- Django日志的配置
做开发离不开日志,以下是我在工作中写Django项目常用的logging配置. BASE_LOG_DIR = os.path.join(BASE_DIR, "log") LOG ...
- linux下文件权限更改(转载)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/qq_33571752/article/d ...
- XMLHttpRequest 对象属性参数参考
readyState:提供当前 HTML 的就绪状态. readyState可能返回的值: 0:请求未初始化(还没有调用 open()). 1:请求已经建立,但是还没有发送(还没有调用 send()) ...
- 解决phpmyadmin出现: Maximum execution time of 300
在mysql用phpmyadmin导入数据的时候出现: Fatal error: Maximum execution time of 300 seconds exceeded in ... 上网查了很 ...
- python连redis测试
python 版本 3.x执行环境需要安装redis模块: pip install redis 执行脚本前,有redis-cli中查询key值: 执行脚本: ********************* ...