【学习笔记】Palindrome Series

SoyTony 近日每天给我讲字符串,我听的受不了了,所以我要来写字符串的博。

前情提要:全是感情,没有证明。

bikuhiku 说我不应该使用“前情提要”这个词,我想了想感觉很对,那换一个词。

前情提要:全是感情,没有证明。

Border Series

Border 有一个性质:对于一个长为 \(n\) 的字符串,其所有长度大于等于 \(\frac{n}{2}\) 的 Border 构成等差数列。

感性理解下,如果大于 \(\frac{n}{2}\),那么前后缀的交集就又是一个 Border。

那么由此可以推出一个性质:一个字符串的 Border 可以划分为 \(\log n\) 段等差序列。

这就是 Border Series。

不知道有啥用,如果有人有例题麻烦给我一个。

Palindrome Series

众所周知,回文串有着与 Border 类似的性质,于是上面的性质可以直接搬过来用。

也就是,对于一个回文串,它的回文串后缀的长度也可以划分为 \(\log n\) 段等差序列。

然后它可以用来解决一些回文串 DP 的问题。

这类问题一般转移式子长这样:

\[f_i=\mathop{\operatorname{OPT}}\limits_{j \le i, s[j, i] \in P}(g(f_{j-1})) \]

其中 \(P\) 为回文串集合。

比如一个简单的例子,求将一个字符串划分为若干个回文串,有多少种划分方案。那么转移式子就应该是:

\[f_i=\sum_{j\le i, s[j, i] \in P}f_{j - 1} \]

枚举 \(j\) 显然没啥前途,我们考虑对原串构造 PAM。那么当建到 \(i\) 这一位时,假如此时在 PAM 上对应的节点为 \(p\),那么转移式子其实就是:

\[f_i=f_{i - len[p]} + f_{i - len[fail[p]]} + f_{i - len[fail[fail[p]]]} + \cdots \]

这样就可以除掉 \(s[j, i] \in P\) 的限制了。但是这样改完之后,一直跳 fail 仍然是 \(O(n)\) 的,复杂度貌似没啥改变。

此时考虑我们上面得到的性质:那么从 \(p\) 到根节点的所有节点可以划分为 \(\log n\) 条链。我们不妨对这 \(\log n\) 条链维护答案。

具体的,设 \(top_u\)\(u\) 节点所在链的链顶的父节点,\(diff_u\)\(len_u-len_{fail[u]}\),这两条信息都可以在构建 PAM 的时候顺便维护出来。

然后考虑维护另一个 DP 数组 \(g_u\) 表示从 \(u\) 节点一直到 \(top_u\) 节点(不含 \(top_u\))的答案和。

由于 \(len\) 构成等差数列,\(g_u\) 是很好转移的。事实上,\(g_u\) 只比 \(g_{fail[u]}\) 多一个答案。可以举一个例子来看怎么转移。

image

假如现在转移到第 \(7\) 位,那么此时 PAM 上对应的节点的 \(g_u\) 应当为 \(f_0+f_2+f_4+f_6\) (即图中打 x 的地方)

image

假设现在转移到了第 \(9\) 位,那么发现实际上现在的 \(g_u\) 仅仅比 \(g_{fail[u]}\) 多出链中最短的串对应的 \(f_i\)(也就是红色的 x)。而当前链中最短的串的长度 \(l = len_{top_u} + diff_u\),那么当前要加上的答案就是 \(f_{i - l}\)

也就是说,\(g_u\) 的转移式子为 \(g_u = g_{fail[u]} + f_{i - l}\)。需要注意 \(fail[u]\) 是否与 \(u\) 在同一个链内,如果不是就不能加上 \(g_{fail[u]}\)

代码大概长这样:

void solve(int i) {
	for (int p = lst; p > 1; p = top[p]) {
		int l = len[top[p]] + diff[p];
		g[p] = f[i - l];
		if (diff[p] == diff[fail[p]]) {
			g[p] += g[fail[p]];
		}
		f[i] += g[p];
	}
}

于是每次插入一个字符之后执行一次 solve 函数即可维护出 \(f\) 数组。

放几道例题:

IITKWPCE - Let us play with strings

这个是纯板子,只不过从求和改成了找最小值。那么把上面的加和改为 \(\min\) 即可。

CF932G Palindrome Partition

题目要求将字符串划分偶数段,求满足 \(s_i=s_{k-i+1}\)\(k\) 为划分的字符串数)的划分方案数。

我们可以将字符串复制一遍翻转过来,然后按照奇偶顺序将两个字符串插入到一起,那么上面的条件就转化成了求偶回文串的划分方案数的问题了。于是直接套上面的板子即可。

CF906E Reverses

题目给出 \(s,t\) 两个字符串,求至少需要翻转 \(s\) 中的多少不相交的区间才能够使 \(s=t\)

同样发现假如按照奇偶将 \(s\)\(t\) 合并,那么如果一个区间翻转之后与 \(t\) 中对应区间相等当且仅当新构造的字符串对应区间为偶回文串,于是直接求该字符串最少划分成多少个回文串。

注意到当长度为 \(1\) 时不需要翻转,所以我们在转移的时候直接判断一下,假如现在最后两位相同那么直接从 \(f_{i-2}\)\(f_i\) 转移一下。注意 \(g_i\) 转移的时候不可以进行这样的特判。(具体看一下上面的图就明白了,转移的时候长度为 \(2\),但是到后面的时候长度就不是 \(2\)了,虽然本题转移了也不会错,但还是要注意转移中的式子不可以跟串的长度有关)

这题还需要输出方案,于是同时记录一下 \(f\)\(g\) 数组的决策点即可。

HDU5340 Three Palindromes

可以整个二维 DP,然后用同样的方式转移即可。

URAL1954 Five Palindromes

怎么又有一个这种题

posted @ 2022-11-18 18:19  APJifengc  阅读(227)  评论(7编辑  收藏  举报