首页 > 其他分享 >Manacher

Manacher

时间:2024-08-03 20:07:13浏览次数:7  
标签:子串 Manacher 间隔 字符串 回文 求出 翻转

马拉车的用处是求出一个字符串以每个位置为回文中心的最大回文半径。

负面效果是会让字符串每两个字符中间插入一个间隔符,增加代码难度。

马拉车的思想是尽量利用之前求出的信息,用以前的回文推出后面的回文。

当前回文中心如果在以前求出的回文范围内,那当前回文中心可以对称到一个对称点上,在以此为基础扩展,当然,继承的信息不能超过之前求出的回文的右端点。

还是读代码复习比较好。

char a[maxn], s[maxn << 1];
// a 是初始字符串,s 是增加间隔符后的字符串
void manacher()
{
	int mr = 0, mid = 0;			// 当前扩展到的 右端点最右的回文串 的右端点、其回文中心
	for (int i = 1; i < n; i++) // 最后一个字符是休止符
	{
		if (i <= mr)								// i ∈ [mid, mr]
			p[i] = min(p[2 * mid - i], mr - i + 1); // min {p[j], len(i, mr)}
		else
			p[i] = 1; // 自己
		for (; s[i - p[i]] == s[i + p[i]];)
			p[i]++;			   // 尝试继续扩展
		if (i + p[i] - 1 > mr) // 更新 mid 和 mr
		{
			mr = i + p[i] - 1;
			mid = i;
		}
	}
}
void init() // 将字符串中间插入间隔符号,使得回文中心位于字符上
{
	s[0] = s[1] = '#';
	for (int i = 1; i <= n; i++)
	{
		s[i * 2] = a[i];
		s[i * 2 + 1] = '#';
	}
	n = n * 2 + 2;
	s[n] = 0;
}

P4555 [国家集训队] 最长双回文串

记录点 \(i\) 作为左端点时最长的回文子串长度 l[i],类似地记录 r[i],要求的时候就对每个间隔符 r[i] + l[i] 就是最大值了。

但这样做只会统计最长回文串长度,还要一步递推求每个点的最大长度。

字符串的题目通常细节很多,需要仔细实现 + 调试。

可以将整个字符串和每个点对应的辅助数组一并输出,并对齐。

printf("%-3d", p[i]); // 位宽三位

UVA11475 Extend to Palindrome

屑题,求完 \(p\) 数组检查有没有回文半径到最右边的回文中心。

P3501 [POI2010] ANT-Antisymmetry

实现细节较多的一道题,思维细节倒是没啥。

就是马拉车的判定回文条件从相等变为相反,然后只能有偶数的子串出现就是了。

/*
大前提:即将扩展的左右端点都在母串内部
扩展条件(满足一个即可):
1. 左右相等且都为间隔符
2. 左右相反
*/
for (; ((s[i - p[i]] == s[i + p[i]] && s[i - p[i]] == '#') || s[i - p[i]] != s[i + p[i]]) && i - p[i] > 0 && i + p[i] < n;)
{
	p[i]++;
}

P1659 [国家集训队] 拉拉队排练

把符合题意的回文丢进桶里,暴力快速幂即可。

P5446 [THUPC2018] 绿绿和串串

这么多题里唯一一道比较好的题目。

显然翻转过后的串一定是实际意义上的(去除间隔符)奇数长度。

除了最后一步,前面翻转的步骤一定是正好翻转到合法位置的,不能截取前缀。

能翻转的条件(满足一个即可):

  1. 回文半径挨到了字符串末尾

    这样翻转后可以保证原串是翻转串的子串。

  2. 回文半径挨到了字符串开头,且其后面子串可以通过翻转的逆操作得到

    这样可以保证翻转后正好是原串的前缀。

字符串题想清楚了才好做,否则会困入细节错误中调不出来。

标签:子串,Manacher,间隔,字符串,回文,求出,翻转
From: https://www.cnblogs.com/tai-chi/p/18340977

相关文章

  • manacher
    manacher用途:找字符串中的最长的回文子串。考虑该问题【模板】manacher求最长回文串长度。该如何做?暴力\(O(n^2)\)就是枚举回文中心,向外拓展。代码太简单了,就不挂了。其实是懒得打二分+hash\(O(n\logn)\)将字符串正向hash,反向hash,枚举回文中心,二分答案即可......
  • 回文结构 manacher & PAM 马拉车 & 回文树
    manacher马拉车通过在每个字符间插入一个特殊字符,使得字符串长度为奇数,从而保证每个字符都有中心。在每个中心记录回文串的长度。马拉车的扩展方式和\(Z\)函数类似。都是通过映射之前已经算过的位置,然后尽可能的向右扩展。复杂度\(O(n)\)通常马拉车的题目统计回文串需要与其他......
  • P3805 【模板】manacher
    原题链接题解细节所有字符的回文半径初始化为1rmax=1ans=1code#include<bits/stdc++.h>#definelllonglongusingnamespacestd;voidsolve(){strings;cin>>s;strings1;for(inti=0;s[i];i++){s1+='#';s1+=......
  • 题解:CodeForces 835 D Palindromic characteristics[区间dp/马拉车Manacher]
    CodeForces835DD.Palindromiccharacteristicstimelimitpertest:3secondsmemorylimitpertest:256megabytes*inputstandardinputoutputstandardoutputPalindromiccharacteristicsofstring\(s\)withlength\(|s|\)isasequenceof\(|s|\)in......
  • 「字符串」Manacher算法(马拉车)/ LeetCode 05(C++)
    给你一个字符串 s,找到 s 中最长的回文子串。示例1:输入:s="babad"输出:"bab"解释:"aba"同样是符合题意的答案。示例2:输入:s="cbbd"输出:"bb"思路我们回想中心扩散法:某字符处的中心扩散完毕后,其实已经将它身前身后的字符段落都搜索过了,那么如果我们搜索其后的字......
  • Manacher学习笔记
    1.用途给定一个串,求该串中最长回文子串的长度2.算法过程2.1.预处理回文串分为两类,奇回文和偶回文,所以对称中点是不确定的,可能是字符也可能是两个字符之间的空隙所以可以在任意两个字符和开头结尾加上同一个奇怪的字符,此时的回文中心就一定是一个字符2.2.算法主体定义数......
  • Manacher
    1问题引入给定一个长度为\(n\)的字符串\(s\),请找出该字符串中所有的回文子串。显然对于一个长度为\(n\)的字符串,其回文子串至多有\(n^2\)个,因此如果一个个统计复杂度必定不会优秀。那如何优化复杂度呢?这就要提到Manacher算法了。在探讨这个算法之前,我们需要先了解其......
  • manacher学习笔记
    小学一下。首先是用一个在回文串题目中的的技巧,用来减少分讨,如果想到这个的话说不定thusc2024d1t1就切了。具体来说,就是在每个字符之间都插入一个#,然后在开头和结尾插入随便两个不同的字符。然后就只有回文中心在字符上的情况了。首先设\(p_{i}\)为当前位置为中心的最大回文半......
  • Manacher 学习笔记
    Manacher是一个求出一个字符串中所有回文子串的利器。记录方法首先我们发现一个问题,一个长为\(S\)的字符串一共有\(S^2\)个子串,所以记录回文子串时不可能记录左右端点。如何解决呢?根据回文串的特点,我们发现,一个回文串,将它的两端各删去一个字符,那么它还是一个回文串。所以我......
  • 算法随笔——manacher
    非常好学习资料manacher求最长回文子串暴力枚举回文中心\([1,n]\),暴力向两边拓展,然后\(checkmax\)。时间复杂度\(O(n^2)\)可以用二分哈希优化至\(O(n\logn)\)算法思路当求解第\(i\)个字符为回文中心的时候,已经知道了\([1,i-1]\)之间的信息。于是引入\(p[i]\):......