[pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=39091399

(CSDN好像有bug,不知道为什么存的草稿覆盖了之前的博客>.<,以后再也不存线上草稿了)

昨天学了马拉车(manacher)算法,今天做了一道例题。虽然并不难,但还是写一写博客,即为民服务,又加深自己的理解。

manacher是高效处理回文串的算法,不过因为只限求回文串,所以适用范围就窄了,但是它仍然有用,所以还是要学。

首先是一个小小的处理技巧。因为回文串可能是奇数可能是偶数,偶数的时候就没有中心字符了,没有著脚点可恼火了。所以我们考虑用没有出现过的字符“#”来表示原串的间隔。eg。ababa->#a#b#a#b#a#。为了避免溢出,访问到不存在的点(’\0’=’\0’),我们再在首尾加上没有出现过的不同字符,eg’+’,’-‘。显然,现在对新串的每一个字符找以此字符为中心的字符串即可。

manacher的思想就是从左到右求出以每个位置为中心的最长字符串(由于回文串很明显的包含和对称性质,以同一位置为中心的字符串自然是包含在最长回文串里),利用回文串的对称性质,对每一个位置利用之前的信息来快速得到答案。近似于扫一遍,所以均摊o(n)(之后详细证明)

那么之前的信息是什么呢?我们记向右延伸最远的回文串(有多个的话,选中心点最靠左的),令其右端点为mx,中心点的下标为id。我们需要处理数组pal[i],表示以i为中心的回文串的右端到i的长度。

下面就是怎么实现的问题了。

对于一个位置i,有三种情况

1、i<=mx,我们可以由对称性得出其关于id的对称点的pal[]



此时易得pal[i]=pal[2*id-i];

2、同样的情况,i<=mx,但是其对应点的范围超出了id的范围。



此时可得pal[i]>=mx-i+1;

由对称性可得,在id范围内的部分i可由2*id-i推来,但外面的部分必定与另一边不同(想想),暴力扩充即可,将mx更新。暴力判断pal[i]能到多少,每次判断成功都等价于mx++,失败则结束。由于mx是单增的,于是判断成功的次数不超过串长次,均摊o(n)

3、i>mx。处理方法与2相同。

放个代码更好理解

  1. void manacher(){
  2. int mx=0,id;
  3. for(int i=1;i<=m;i++){
  4. if(mx>=i) pal[i]=min(mx-i+1,pal[2*id-i]);
  5. else pal[i]=1;
  6. while(s[i-pal[i]]==s[i+pal[i]]) pal[i]++;
  7. if(i+pal[[i]-1>mx)
  8. mx=i+pal[i]-1,id=i;
  9. }
  10. }
  11. }

由代码可以也可以看出,mx是单增的,均摊o(n)

此外,manacher算法还引出了一个——

极重要的性质



再来看这张图,我们发现,如果mx不更新,就不会出现本质不同的回文子串,因为前面已经出现过了;而每扩展一次mx,最多新出现一个本质不同的回文子串。

于是得到性质:#一个字符串最多只有n个本质不同的回文子串#。这个性质很重要,有些题会用到,需要这个性质去分析。

基础讲完了,终于可以放题了:D

Description

母亲节就要到了,小 H 准备送给她一个特殊的项链。这个项链可以看作一个用小写字

母组成的字符串,每个小写字母表示一种颜色。为了制作这个项链,小 H 购买了两个机器。第一个机器可以生成所有形式的回文串,第二个机器可以把两个回文串连接起来,而且第二个机器还有一个特殊的性质:假如一个字符串的后缀和一个字符串的前缀是完全相同的,那么可以将这个重复部分重叠。例如:aba和aca连接起来,可以生成串abaaca或 abaca。现在给出目标项链的样式,询问你需要使用第二个机器多少次才能生成这个特殊的项链。

Input

输入数据有多行,每行一个字符串,表示目标项链的样式。

Output

多行,每行一个答案表示最少需要使用第二个机器的次数。

Sample Input

abcdcba

abacada

abcdef

Sample Output

0

2

5

HINT

每个测试数据,输入不超过 5行

每行的字符串长度小于等于 50000

先用manacher跑出pal[ ]数组,因为题目说可以重合,于是就转换成了经典的区间覆盖问题,贪心即可。

代码

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. const int N=50000+5;
  6. int len,pal[N*2];
  7. char s[N],a[N*2];
  8. struct Node{
  9. int le,ri;
  10. }qu[N*2];
  11. bool cmp(Node a,Node b){
  12. return a.le<b.le;
  13. }
  14. void insert(){
  15. memset(a,0,sizeof(a));
  16. int lena=-1;
  17. a[++lena]='+';
  18. for(int i=0;i<len;i++){
  19. a[++lena]='#';
  20. a[++lena]=s[i];
  21. }
  22. a[++lena]='#';
  23. a[++lena]='-';
  24. len=lena-1;
  25. }
  26. void manacher(){
  27. int mx=0,id;
  28. for(int i=1;i<=len;i++){
  29. if(mx>=i) pal[i]=min(mx-i+1,pal[2*id-i]);
  30. else pal[i]=1;
  31. while(a[i-pal[i]]==a[i+pal[i]]) ++pal[i];
  32. if(mx<i+pal[i]-1)
  33. mx=i+pal[i]-1,id=i;
  34. }
  35. }
  36. int fugai(){
  37. int ans=0,far=1;
  38. int i=1;
  39. for(i=1;qu[i].le<=1;i++)
  40. if(qu[i].ri>qu[far].ri) far=i;
  41. while(i<=len){
  42. ans++;
  43. int tmp=far;
  44. for(;qu[i].le<=qu[far].ri;i++)
  45. if(qu[i].ri>qu[tmp].ri) tmp=i;
  46. far=tmp;
  47. }
  48. return ans;
  49. }
  50. int main(){
  51. while(scanf("%s",s)!=EOF){
  52. len=strlen(s);
  53. insert();
  54. manacher();
  55. memset(qu,0,sizeof(qu));
  56. for(int i=1;i<=len;i++)
  57. qu[i].le=i-pal[i]+1,qu[i].ri=i+pal[i]-1
  58. sort(qu+1,qu+len+1,cmp);
  59. printf("%d\n",fugai()-1);
  60. }
  61. return 0;
  62. }

manacher(马拉车)算法详解+例题一道【bzoj3790】【神奇项链】的更多相关文章

  1. Manacher(马拉车)算法详解

    给定一个字符串,求出其最长回文子串 eg:  abcba 第一步: 在字符串首尾,及各字符间各插入一个字符(前提这个字符未出现在串里). 如  原来ma  /*  a    b a    b   c ...

  2. 算法进阶面试题01——KMP算法详解、输出含两次原子串的最短串、判断T1是否包含T2子树、Manacher算法详解、使字符串成为最短回文串

    1.KMP算法详解与应用 子序列:可以连续可以不连续. 子数组/串:要连续 暴力方法:逐个位置比对. KMP:让前面的,指导后面. 概念建设: d的最长前缀与最长后缀的匹配长度为3.(前缀不能到最后一 ...

  3. Manacher(马拉车)算法(jekyll迁移)

    layout: post title: Manacher(马拉车)算法 date: 2019-09-07 author: xiepl1997 cover: 'assets/img/manacher.p ...

  4. BSGS(Baby Steps,Giant Steps)算法详解

    BSGS(Baby Steps,Giant Steps)算法详解 简介: 此算法用于求解 Ax≡B(mod C): 由费马小定理可知: x可以在O(C)的时间内求解:  在x=c之后又会循环: 而BS ...

  5. FloodFill算法详解及应用

    啥是 FloodFill 算法呢,最直接的一个应用就是「颜色填充」,就是 Windows 绘画本中那个小油漆桶的标志,可以把一块被圈起来的区域全部染色. 这种算法思想还在许多其他地方有应用.比如说扫雷 ...

  6. 《算法详解:C++11语言描述》已出版

    经过漫长的编写.修订和印刷过程,书籍<算法详解:C++11语言描述>终于出版了!目前本书已在各大电商平台上架,搜索书名即可找到对应商品.本书的特色在于: 介绍最新的C++11.C++14和 ...

  7. BM算法  Boyer-Moore高质量实现代码详解与算法详解

    Boyer-Moore高质量实现代码详解与算法详解 鉴于我见到对算法本身分析非常透彻的文章以及实现的非常精巧的文章,所以就转载了,本文的贡献在于将两者结合起来,方便大家了解代码实现! 算法详解转自:h ...

  8. kmp算法详解

    转自:http://blog.csdn.net/ddupd/article/details/19899263 KMP算法详解 KMP算法简介: KMP算法是一种高效的字符串匹配算法,关于字符串匹配最简 ...

  9. 机器学习经典算法详解及Python实现--基于SMO的SVM分类器

    原文:http://blog.csdn.net/suipingsp/article/details/41645779 支持向量机基本上是最好的有监督学习算法,因其英文名为support vector  ...

随机推荐

  1. iterm2+vim使用

    iterm2+vim 终端切换为iterm2+zsh+oh my zsh,确实好用. I term2常用快捷键记录 新建标签:cmd+t 关闭标签:cmd+w 切换标签:cmd+数字, 切换全屏:cm ...

  2. shell sort 排序大讨论

    转自http://roclinux.cn 本原创文章属于<Linux大棚>博客,博客地址为http://roclinux.cn.文章作者为rocrocket. === [正文开始]有时候学 ...

  3. nginx教程全集汇总

    Nginx基础1.  nginx安装:httpwww.ttlsa.comnginxnginx-install-on-linux2.  nginx 编译参数详解(运维不得不看):http://www.t ...

  4. 【bzoj2306】[Ctsc2011]幸福路径 倍增Floyd

    题目描述 一张n个点的有向图,每个点有一个权值.一开始从点$v_0$出发沿图中的边任意移动,移动到路径上的第$i$个点 输入 每一行中两个数之间用一个空格隔开. 输入文件第一行包含两个正整数 n,  ...

  5. 【bzoj1706】[usaco2007 Nov]relays 奶牛接力跑 离散化+倍增Floyd

    题目描述 FJ的N(2 <= N <= 1,000,000)头奶牛选择了接力跑作为她们的日常锻炼项目.至于进行接力跑的地点 自然是在牧场中现有的T(2 <= T <= 100) ...

  6. 刷题总结——Interval query(hdu4343倍增+贪心)

    题目: Problem Description This is a very simple question. There are N intervals in number axis, and M ...

  7. org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [WebApp] in context with path关于数据库库的问题

    1.在本地~~把你的查询的sql打印出来~~~然后拿到测试库里面执行一遍~~然后拿到正式库里面在执行一遍  2.看生产和本地~~1).代码不同步:2).就是数据为空问题 3.也有可能是数据库配置文件问 ...

  8. How to secure remote desktop connections using TLS/SSL

    How to secure remote desktop connections using TLS/SSL based authentication Requirement When you ena ...

  9. noi2017 T1 整数 ——线段树

    loj.ac上有  题目传送门 不过我还是把题目搬过来吧 整数(integer)[题目背景]在人类智慧的山巅,有着一台字长为 1048576 位的超级计算机,著名理论计算机科 学家 P 博士正用它进行 ...

  10. MTK_GPIO口的定制

    http://blog.csdn.net/zuoyioo7/article/details/77863291如果需要定制GPIO口呢,需要使用mediatek/dct/DrvGen.exe工具,点击O ...