前言

皆移植于原csdn博客,略有修改

所讲例题
洛谷 3805【模板】manacher算法
JZOJ 2682 洛谷 4555 最长双回文串
JZOJ 1950 洛谷 1659 拉拉队排练

洛谷 3805【模板】manacher算法

题目

找到一个字符串中的最长回文子串


分析

首先字符串的长度为\(n\leq 11000000\),显然只能用\(O(n)\)的时间完成这道题目,首先朴素的方法就是\(O(n^2)\),也就是枚举中间点向外扩展,

但是这样的坏处在哪里呢,就是这样扩展很有可能找不到最优解而浪费了时间,那应该怎么做呢?

那就可以引进一种神奇的算法,manacher

那么这是什么神奇的东西呢,首先对于长度奇偶性可以在字符串中间填充分隔符,这样字符串就一定是奇数,为了避免越界,还要在开头加一个分隔符。

那要记录三样东西,首先是\(p[i]\)表示中点为\(i\)时的最长回文串的半径,然后那么显而易见答案就是\(max\{p[i]-1\}\),那问题是答案怎么算,这是一个大问题

再首先,我们要记录两个东西,\(mid\)表示当前找到的最长回文串的中点,\(mx\)表示该回文串的右边界。

首先对于每一个\(i\),若\(i<mx\)说明还是有希望的,否则就只能像纯模拟一样\(p[i]=1\)

当然不管怎么样还是得加上这句话\(while (s[i-p[i]]==s[i+p[i]]) ++p[i];\)

那\(if (mx<i+p[i]) mx=i+p[i],mid=i;\)是为什么,显然可知是更新最长回文子串

但问题是\(manacher\)如何优化呢,那就是\(i<mx\)的情况了

那么首先设\(j=2*i-mid\),也就是对于\(mid\),\(i\)的对称点,可以通过\((j+i)\div 2=mid\)得到。

那么分类讨论,首先先配两张图(蓝色所示为j的答案范围,浅绿所示为i的答案范围,区间为mid的答案范围)

  • \(j\)的答案范围超出\(mid\)的答案范围,那么如果\(i\)像\(j\)那样求答案,就违背了\(mid\)的答案,故假设不成立,所以\(p[i]=mx-i\)

  • \(j\)的答案范围小于\(mid\)的答案范围,那么如果\(j\)像\(i\)那样求答案,就违背了\(j\)的答案,故假设不成立,所以\(p[i]=p[j]\)

  • \(j\)的答案范围等于\(mid\)的答案范围,则两者均可

综上所述,就可以得到上面的代码


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
char s[22000015]; int n,ans,p[22000015];
inline signed max(int a,int b){return (a>b)?a:b;}
inline signed min(int a,int b){return (a<b)?a:b;}
inline signed manacher(char *s,int len){
rr int maxlen=1,mx=0,mid=0;
for (rr int i=1;i<len;++i){
p[i]=mx>i?min(p[(mid<<1)-i],mx-i):1;
while (s[i-p[i]]==s[i+p[i]]) ++p[i];
if (mx<i+p[i]) mx=i+p[i],mid=i;
maxlen=max(maxlen,p[i]-1);
}
return maxlen;
}
signed main(){
rr char c=getchar(); s[0]='!';
while (!isalpha(c)) c=getchar();
while (isalpha(c)) s[++n]='|',s[++n]=c,c=getchar();
s[++n]='|'; ans=manacher(s,n);
return !printf("%d",ans);
}

洛谷 4555 最长双回文串

题目

输入长度为\(n\)的串\(S\),求\(S\)的最长双回文子串\(T\),即可将\(T\)分为两部分\(X\),\(Y\),\((|X|,|Y|≥1∣X∣,∣Y∣≥1)\)且\(X\)和\(Y\)都是回文串。


分析

那么在manacher的同时,可以记录最长回文串的最右端的长度\(l[i+p[i]-1]=p[i]-1\)和最左端的长度\(r[i-p[i]+1]=p[i]-1\),

然后用O(n)的时间更新,也就是\(l[i]=max\{l[i+2]-2,l[i]\},r[i]=max\{r[i-2]-2,r[i]\}\)

为什么呢,因为首先最长回文串内的回文子串答案是没有更新的,那为什么要更新呢,

因为最长双回文串的两个回文串不一定是最长的,那么统计\(max\{l[i]+r[i]\}\)即可


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
char s[200015]; int n,ans,p[200015],l[200015],r[200015];
inline signed max(int a,int b){return (a>b)?a:b;}
inline signed min(int a,int b){return (a<b)?a:b;}
inline void manacher(char *s,int len){
rr int mx=0,mid=0;
for (rr int i=1;i<len;++i){
p[i]=mx>i?min(p[(mid<<1)-i],mx-i):1;
while (s[i-p[i]]==s[i+p[i]]) ++p[i];
if (mx<i+p[i]) mx=i+p[i],mid=i;
l[i+p[i]-1]=max(l[i+p[i]-1],p[i]-1);
r[i-p[i]+1]=max(r[i-p[i]+1],p[i]-1);
}
for (rr int i=1;i<=len;i+=2) r[i]=max(r[i],r[i-2]-2);
for (rr int i=len;i>0;i-=2) l[i]=max(l[i],l[i+2]-2);
for (rr int i=1;i<=len;i+=2) if (l[i]&&r[i]) ans=max(ans,l[i]+r[i]);
}
signed main(){
rr char c=getchar(); s[0]='!';
while (!isalpha(c)) c=getchar();
while (isalpha(c)) s[++n]='|',s[++n]=c,c=getchar();
s[++n]='|'; manacher(s,n);
return !printf("%d",ans);
}

洛谷 1659 拉拉队排练

题目

问前\(k\)个最长奇回文串长度的乘积


分析

在manacher的基础上开个桶统计长度个数,当然是一个前缀和,因为每个最长回文串其实包含着一些回文子串,然后一定要记得快速幂


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int mod=19930726; typedef long long ll;
char s[2000015]; int n,p[2000015],b[2000015];
inline signed max(int a,int b){return (a>b)?a:b;}
inline signed min(int a,int b){return (a<b)?a:b;}
inline void manacher(char *s,int len){
rr int mx=0,mid=0;
for (rr int i=1;i<len;++i){
p[i]=mx>i?min(p[(mid<<1)-i],mx-i):1;
while (s[i-p[i]]==s[i+p[i]]) ++p[i];
if (mx<i+p[i]) mx=i+p[i],mid=i;
if (!(p[i]&1)) ++b[p[i]-1];
}
}
inline ll ksm(ll x,ll y){
rr ll ans=1;
for (;y;y>>=1,x=(x*x)%mod)
if (y&1) ans=(ans*x)%mod;
return ans;
}
signed main(){
rr ll res=1,k;
scanf("%*d%lld",&k);
rr char c=getchar(); s[0]='!';
while (!isalpha(c)) c=getchar();
while (isalpha(c)) s[++n]='|',s[++n]=c,c=getchar();
s[++n]='|'; manacher(s,n);
for (rr int i=n,sum=0;i>0;i-=2){
sum+=b[i];
if (k>=sum){
res=(res*(ksm(i,sum)))%mod;
k-=sum;
}else{
res=(res*(ksm(i,k)))%mod;
k=0; break;
}
}
if (k>0) res=-1;
return !printf("%lld",res);
}

Manacher小记的更多相关文章

  1. 【2018.07.28】(字符串/回文串)学习Manacher算法小记

    主要是应用在回文串啦,原理也理解了老半天,如果没有图片的话,我也看不太懂它的原理 学习的灵感来源来自于:https://segmentfault.com/a/1190000008484167 /* 最 ...

  2. Manacher 算法学习小记

    概要 一个字符串有多少个回文的字串?最多有 \(O(n^2)\) 级别个.但 Manacher 算法却可以用 \(O(n)\) 的时间复杂度解决这个问题.同时 Manacher 算法实现非常简单. 一 ...

  3. [原]Paste.deploy 与 WSGI, keystone 小记

    Paste.deploy 与 WSGI, keystone 小记 名词解释: Paste.deploy 是一个WSGI工具包,用于更方便的管理WSGI应用, 可以通过配置文件,将WSGI应用加载起来. ...

  4. HDU3068 回文串 Manacher算法

    好久没有刷题了,虽然参加过ACM,但是始终没有融会贯通,没有学个彻底.我干啥都是半吊子,一瓶子不满半瓶子晃荡. 就连简单的Manacher算法我也没有刷过,常常为岁月蹉跎而感到后悔. 问题描述 给定一 ...

  5. MySql 小记

    MySql  简单 小记 以备查看 1.sql概述 1.什么是sql? 2.sql发展过程? 3.sql标准与方言的关系? 4.常用数据库? 5.MySql数据库安装? 2.关键概念 表结构----- ...

  6. manacher算法专题

    一.模板 算法解析:http://www.felix021.com/blog/read.php?2040 *主要用来解决一个字符串中最长回文串的长度,在O(n)时间内,线性复杂度下,求出以每个字符串为 ...

  7. BZOJ2342 Manacher + set

    题一:别人介绍的一道题,题意是给出一个序列,我们要求出一段最常的连续子序列,满足:该子序列能够被平分为三段,第一段和第二段形成回文串,第二段和第三段形成回文串. 题二:BZOJ2342和这题非常的相似 ...

  8. Git小记

    Git简~介 Git是一个分布式版本控制系统,其他的版本控制系统我只用过SVN,但用的时间不长.大家都知道,分布式的好处多多,而且分布式已经包含了集中式的几乎所有功能.Linus创造Git的传奇经历就 ...

  9. 广州PostgreSQL用户会技术交流会小记 2015-9-19

    广州PostgreSQL用户会技术交流会小记 2015-9-19 今天去了广州PostgreSQL用户会组织的技术交流会 分别有两个session 第一个讲师介绍了他公司使用PostgreSQL-X2 ...

  10. 东哥读书小记 之 《MacTalk人生元编程》

         一直以来的自我感觉:自己是个记性偏弱的人.反正从小读书就喜欢做笔记(可自己的字写得巨丑无比,尼玛不科学呀),抄书这事儿真的就常发生俺的身上. 因为那时经常要背诵课文之类,反正为了怕自己忘记, ...

随机推荐

  1. React Native如何每次唤醒APP都执行一段代码

    最近想要做一个类似于淘宝每次打开会根据用户剪贴板内容弹出对应商品的功能.要完成这个功能需要每次唤醒APP都读取一次剪贴板. 1.监听 && 销毁 1 async componentDi ...

  2. portainer docker可视化工具

    下载可视化工具 docker pull portainer/portainer 启动portainer --restart=always 只要挂掉了 就自动重启 docker run -d -p 80 ...

  3. 05、etcd 读请求执行流程

    本篇内容主要来源于自己学习的视频,如有侵权,请联系删除,谢谢. 1.etcd读请求概览 etcd是典型的读多写少存储,在我们实际业务场景中,读一般占据2/3以上的请求.一个读 请求从client通过R ...

  4. 51从零开始用Rust编写nginx,江湖救急,TLS证书快过期了

    wmproxy wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 负载均衡, 静态文件服务器,websocket代理,四层TCP/UDP转发,内网穿透等,会将实 ...

  5. 【Azure 应用服务】使用App Service for Linux/Container时,如果代码或Container启动耗时大于了230秒,默认会启动失败。

    问题描述 使用App Service for Linux/Container时,从Docker的日志中,我们可以看见有 warmup 行为,而此行为默认时间为230秒,如果超出了这个时间,就会导致Co ...

  6. Java 对属性赋值的位置 执行的先后顺序

    1 package com.bytezreo.block; 2 3 /** 4 * 5 * @Description 对属性赋值的位置: 6 * @author Bytezero·zhenglei! ...

  7. C++ //案列-员工分组 ( 容器存放,查找,打印,统计,宏定义 ,随机)

    //案列-员工分组//描述:公司招聘10个员工(ABCDEFGHIJ),10名指派员工进入公司,需要指派那个员工在那个部门工作//员工信息有:姓名 工资组成: 部门分为:策划 美术 研发//随机给10 ...

  8. 5-事件组&任务通知

    获取某个事件 获取若干事件中的某个事件 获取若干事件中的全部事件 !!!!不可获得若干事件中的几个事件 创建事件组,设置事件,等待事件 static EventGroupHandle_t xEvent ...

  9. stm32 boot0硬件接法导致的概率性启动失败问题总结和反思

    概要  问题概要,板子在稳压电源上工作很好,可一旦接了电池,stm32就会出现概率性的无法启动.加上项目比较急,这个问题阻塞一直无法量产.真是非常的要命啊. 思路分析  既然是不同的电源会导致这个问题 ...

  10. C语言中的强制转换

    许久没有遇到的问题   C语言真是博大精深,越使用它,就越发感觉到它的威力和恐怖,最近在做算法的时候,遇到了一个强转的错误,把人折腾的够受,这次要好好梳理一下了,希望下次不能再犯此类的问题. 强制转换 ...