manacher学习笔记
小学一下。
首先是用一个在回文串题目中的的技巧,用来减少分讨,如果想到这个的话说不定thusc2024 d1t1就切了。具体来说,就是在每个字符之间都插入一个#,然后在开头和结尾插入随便两个不同的字符。然后就只有回文中心在字符上的情况了。
首先设为当前位置为中心的最大回文半径。mr为当前做到的回文串的右端点,mid为当前做到的回文串的中心。
首先i肯定大于mid,因为根据代码,mid由i更新,而i是一直在前进的
分两类讨论:
mid<i<mr
p[i]=min(p[mid*2-i],mr-i+1);
分两部分解释。设j为i关于mid的对称点,ml为mr关于mid的对称点。如果i+p[j]>mr,那么我们不能保证[i-p[j],i+p[j]]是回文串,所以为mr-i+1。否则根据对称性,p[i]就等于p[j]
i>=mr
直接暴力向两边拓展即可。
时间复杂度证明
如果当前p[i]==p[j]那么说明不能向两边拓展了,就不会进到while里去。如果当前p[i]=mr-i+1,那么就可能向两边拓展,同时更新mr。向两边拓展也更新了mr,所以每次的while循环都对应着mr的拓展,每次mr的拓展都对应着while循环,因为mr最多为len,那么最多进len次while,所以时间复杂度线性
注意manacher求的是p[i]就像kmp求的是nxt一样,用的是这个工具来解决题目,而不是只是记住模板上的东西。
然后做了%%%lyc%%%给的题单,感觉会了
P4555
一个比较自然的想法就是将两个字符串拼在一起。具体来说就是枚举一个中心,然后长度加上以i+p[i]+1为开头的最长字符串长度。枚举好求,考虑后面怎么求。我们可以从后往前,l[i]=max(l[i+1]-2,p[i]),然后就以了。
P1659
manacher还会和一些乘法原理搞在一起然后就有一些奇妙的计数题。比如这题。
我们要首先知道p[i]代表的是最长回文半径。所以就有回文半径为1-p[i]的回文串各一个。这个可以用差分给他优化掉。我们统计出来后,我们就可以从高向低枚举,再用个快速幂就可以了。
P4287
计数题。有两种思路,一种是从kmp的角度考虑的,一种是从manacher的角度考虑的。
1.考虑在kmp的过程中,如果有一个匹配到了,那么就要加上有多少个i-p[i]<=j&&i+p[i]>=j+m的,这可以看成给一段区间进行区间加,然后再进行区间取min。第一个用差分实现,第二个用单调队列实现。时间
2.考虑在,manacher的过程中,找到了一个最长回文串,那么就加上它的所有贡献。我们可以将s2出现的位置的b数组加上1,那么问题就变成了。我们可以这样搞
显然s1,s3就是i*b[i]的前缀和,s2就是b[i]的前缀和,这都可以求出
CF17E
首先两个回文串相交的条件就是一个回文串的右端点大于等于一个回文串的左端点。所以我们可以统计有多少个右端点大于i-p[i]。因为p[i]代表的是最长回文半径所以我们就有一个求和式子
我们可以搞两个线段树,一个存i*b[i]前缀和一个存b[i]前缀和,然后统计完答案后[i,i+p[i]]整体加就可以了。对于i+b[i]也无非就是线段树里稍微搞一下就行了,这是的做法
当然我们也可以统计一个串和所有串的答案,最后再减去重复的,但因为这题要取模,所以不好搞(开个long long貌似可以?),这样是的
最后我们可以正难则反。先求出所有的,再减去不相交的,我们可以统计出以i为开头和以i为结尾的回文串个数,sum1,sum2然后搞一个sum2的前缀和,然后减掉sum1[i]*sum2[i-1]这个做法非常的好,我的做法简直是依托。这种问题经常有,不知道为什么。
P3501
manacher是字符串算法,但它不是回文串算法,我觉得以这个作为manacher学习笔记的结尾非常适合。manacher能做的是字符之间有匹配关系,且这个匹配关系大概长这个样子
这个样子的manacher应该都能做,这也算是对manacher的一种拓展了吧
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!