前置知识

首先你得会manacher,并理解manacher为什么是对的(不用理解为什么它是$O(n)$,这个大概记住就好了,不过理解了更方便做$PAM$的题)

什么是回文自动机?

回文自动机(Palindrome Automaton),是一类有限状态自动机,能识别一个字符串的所有回文子串

它可简化构建出回文树

回文自动机的构造

网上资料很多,不拿出来一步步说了,说一下数组意义、放个板子

$len[u]$表示节点$u$代表的回文串的长度

$ch[u][c]$代表在$u$的回文串两端添加字符$c$得到的新回文串节点

$fail[u]$表示节点$u$的回文串的最长的回文后缀所在的节点

  1. char s[300010];
  2. int n;
  3. //这个板子里面的num表示当前节点的回文串出现了几遍
  4. namespace pam{
  5. int fail[300010],num[300010],len[300010],ch[300010][26],last,cnt;
  6. inline int newnode(int w){len[++cnt]=w;return cnt;}
  7. void init(){
  8. s[0]=-1;cnt=-1;fail[0]=1;last=0;
  9. newnode(0);newnode(-1);//插入两个根节点,设置fail
  10. }
  11. inline int getfail(int cur,int pos){
  12. while(s[pos-len[cur]-1]!=s[pos]) cur=fail[cur];//跳fail
  13. return cur;
  14. }
  15. void insert(int x){
  16. int c=(s[x]-'a'),cur=getfail(last,x);
  17. if(!ch[cur][c]){//新建节点
  18. int now=newnode(len[cur]+2);
  19. fail[now]=ch[getfail(fail[cur],x)][c];
  20. ch[cur][c]=now;
  21. }
  22. num[last=ch[cur][c]]++;
  23. }
  24. }

几个容易写错的点:

fail初始化的时候,如果多组数据并且在newnode里面初始化信息,那么在init的时候记得把fail放到newnode后面

插入的时候函数传进去的是位置

newnode是len[cur]+2不是+1

一些拓展

节点上

首先显然可以统计这个节点的回文串出现次数

统计次数的时候还要加上$fail$树上子树内的所有节点的出现次数

对于一类回文串拥有某个和其$fail$树有关的性质的题目,可以记录一个$trans$,和跳$fail$一样跳,最后用$bfs$来做$dp$或者递推

关于求最小回文串分解

这个问题是问可以把一个字符串分解成最少多少个回文串

解决的方法:

考虑一个显然的$dp$:$dp[i]=dp[j-1]+1 (s[i...j]=palindrome)$

记录一个$anc[u]$

如果$len[u]-len[fail[u]]==len[fail[u]]-len[fail[fail[u]]]$,那么$anc[u]=anc[fail[u]]$

否则$anc[u]=u$

对于$u$的所有跳上去的$anc$集合$S$,我们发现,这个集合中的元素构成一个等差数列,相邻的两项差代表一种从当前点前面递推到当前点的回文串长度

对于每个回文树节点记录$tmp[u]=min(tmp[i-len[anc[u]],tmp[fail[u]])$,然后用这个$tmp[u]+1$来更新当前节点的$dp$,然后$u=fail[anc[u]]$往上跳,直到到达根

证明网上有论文,这里放个代码

  1. inline void insert(int x){
  2. int c=s[x]-'a',cur=getfail(last,x);
  3. val[x]=1e9;
  4. if(!ch[cur][c]){
  5. int now=newnode(len[cur]+2);
  6. fail[now]=ch[getfail(fail[cur],x)][c];
  7. ch[cur][c]=now;
  8. anc[now]=((fail[now]>1&&len[now]-len[fail[now]]==len[fail[now]]-len[fail[fail[now]]])?anc[fail[now]]:now);
  9. }
  10. last=ch[cur][c];
  11. for(cur=ch[cur][c];cur>1;cur=fail[anc[cur]]){
  12. tval[cur]=val[x-len[anc[cur]]];
  13. tpos[cur]=x-len[anc[cur]];
  14. if(anc[cur]!=cur&&tval[fail[cur]]<tval[cur]) tval[cur]=tval[fail[cur]],tpos[cur]=tpos[fail[cur]];
  15. if(val[x]>tval[cur]+1) val[x]=tval[cur]+1,pos[x]=tpos[cur];
  16. }
  17. }

省选算法学习-回文自动机 && 回文树的更多相关文章

  1. Palindromic Tree 回文自动机-回文树 例题+讲解

    回文树,也叫回文自动机,是2014年被西伯利亚民族发明的,其功能如下: 1.求前缀字符串中的本质不同的回文串种类 2.求每个本质不同回文串的个数 3.以下标i为结尾的回文串个数/种类 4.每个本质不同 ...

  2. manacher算法学习(求最长回文子串长度)

    Manacher总结 我的代码 学习:yyb luogu题目模板 xzy的模板 #include<iostream> #include<cstdlib> #include< ...

  3. 省选算法学习-数据结构-splay

    于是乎,在丧心病狂的noip2017结束之后,我们很快就要迎来更加丧心病狂的省选了-_-|| 所以从写完上一篇博客开始到现在我一直深陷数据结构和网络流的漩涡不能自拔 今天终于想起来写博客(只是懒吧.. ...

  4. 省选算法学习-插头dp

    插头dp?你说的是这个吗? 好吧显然不是...... 所谓插头dp,实际上是“基于连通性的状态压缩dp”的简称,最先出现在cdq的论文里面 本篇博客致力于通过几道小小的例题(大部分都比较浅显)来介绍一 ...

  5. 省选算法学习-BSGS与exBSGS与二次剩余

    前置知识 扩展欧几里得,快速幂 都是很基础的东西 扩展欧几里得 说实话这个东西我学了好几遍都没有懂,最近终于搞明白,可以考场现推了,故放到这里来加深印象 翡蜀定理 方程$ax+by=gcd(a,b)$ ...

  6. 省选算法学习-dp优化-四边形不等式

    嗯......四边形不等式的确长得像个四边形[雾] 我们在dp中,经常见到这样一类状态以及转移方程: 设$dp\left[i\right]\left[j\right]$表示闭区间$\left[i,j\ ...

  7. 算法学习——从bzoj2286开始的虚树学习生活

    [原创]转载请标明原作者~ http://www.cnblogs.com/Acheing/ 题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2 ...

  8. 【算法学习】【洛谷】树链剖分 & P3384 【模板】树链剖分 P2146 软件包管理器

    刚学的好玩算法,AC2题,非常开心. 其实很早就有教过,以前以为很难就没有学,现在发现其实很简单也很有用. 更重要的是我很好调试,两题都是几乎一遍过的. 介绍树链剖分前,先确保已经学会以下基本技巧: ...

  9. 数据结构和算法学习笔记十五:多路查找树(B树)

    一.概念 1.多路查找树(multi-way search tree):所谓多路,即是指每个节点中存储的数据可以是多个,每个节点的子节点数也可以多于两个.使用多路查找树的意义在于有效降低树的深度,从而 ...

随机推荐

  1. Python 初始—(项目 目录结构)

    在os 包下,给出 import os ,os.path.abspath(__file__)获取当前文件的相对路径,os.path.dirname 获取当前文件所在的文件夹目录 print(os.pa ...

  2. 【学时总结】 ◆学时·II◆ IDA*算法

    [学时·II] IDA*算法 ■基本策略■ 如果状态数量太多了,优先队列也难以承受:不妨再回头看DFS-- A*算法是BFS的升级,那么IDA*算法是对A*算法的再优化,同时也是对迭代加深搜索(IDF ...

  3. Java的按值传递和按引用传递解说

    在网上看到的一个帖子解释Java的按值传递和按引用传递,感觉挺全面,就转过来,以供以后学习参考: 1:按值传递是什么 指的是在方法调用时,传递的参数是按值的拷贝传递.示例如下: public clas ...

  4. 如何快速查看mysql数据文件存放路径?

    进入mysql终端 mysql>show variables like '%datadir%'; 出来的结果即是!

  5. U盘装机记录

    U盘装机记录 1. 将U盘制作为启动盘(安装PE文件到U盘). (1)准备材料 8G以上U盘一个 一个可信的启动盘制作工具(这里是用的老毛桃) (2)将U盘插入电脑,单击老毛桃客户端(出现如下图所示的 ...

  6. UIView控件 概况

    一.UIKit结构图 ------------------------------------------------------------------------------- @interfac ...

  7. C语言进阶——分支语句06

    if分支语句分析: if语句用于根据条件选择执行语句 else不能独立存在且总是与在它之前的最近if相匹配 esle语句后可以连接其他if语句 用法如下: if(condition) { //stat ...

  8. python基础之模块part1

    模块: 模块本质上就是一个Python程序. 所有说是对象的,一定可以通过  对象.方法  来实现某些操作. 模块种类: 内置模块 第三方模块 自定义模块 import在查找模块的顺序:内置模块--- ...

  9. sql里的多行多列转一行多列小技巧

    ---恢复内容开始--- [ 今天下午接受了一个紧急小任务,是将一组比赛记录统计出来,将象棋游戏玩家的两条记录在一行里面显示,进数据库看之后是首先想到的是行转列,但是一开始就觉得不对,后来写到一半确实 ...

  10. 万年历Calendar、js修改日期

    //万年历 Calendar cal = Calendar.getInstance(); cal.add(Calendar.DATE,-1); //改变日期,改变年份.月份类似 SimpleDateF ...