2025.7.24 字符串

P4824 [USACO15FEB] Censoring S

Hint:经典模型,考虑用栈维护,再记录每次匹配到的位置.

一个栈维护的经典例题是:给定括号序列,任意相邻的匹配括号会被消除,输出剩下的括号序列. 显然,遇到左括号直接入栈,右括号直接判断栈顶是不是匹配的左括号,是则弹出,否则入栈即可.

回到这个题,相当于把括号匹配加强成了模式串匹配,考虑 kmp 维护,一旦匹配上最后一位就弹出栈中完整的模式串. 但是弹出栈之后我们需要从栈顶之前匹配上的位置接着匹配,所以再单独记录一下每个匹配到的位置即可.

时间复杂度是 \(O(n)\),因为每个字符至多入栈一次,出栈一次.

P3435 [POI 2006] OKR-Periods of Words

Hint:若长度为 \(n\) 的串有一个长度为 \(k\) 的 border,则必定对应一个长度为 \(n-k\) 的周期.

首先理解题意,发现题目定义的周期限制是假的,因为若 \(A\)\(\overbrace {QQQ\cdots}^{k个Q}\) 前缀,那么最长周期只可能是 \(Q'=\overbrace{QQ\cdots}^{k-1个Q}\),也就是说 \(A\)\(Q'Q'\) 前缀. 所以题目定义的最长周期一定是一般字符串的最长周期.

上面的结论根据定义其实很好理解,于是原题转换为求最小 border. 使用 kmp 容易求出最长 border,最短 border 可以想到一直跳 fail,考虑这样的复杂度为什么是对的. 类似 kmp 的,每次 \(j\) 至多多增加 \(1\),增量是 \(O(n)\) 的. 每次无论是为了匹配还是为了找最短 border,每次跳 fail \(j\) 都至少减去 \(1\),由于增量 \(O(n)\),所以跳的次数也就是 \(O(n)\) 了. 同时可以用记忆化进一步加快跳的过程,也就是每次找到最小 border 时更新 fail.

下面再补一道之前没来及总结的题

P2375 [NOI2014] 动物园

Hint:跳 fail 的原理可以用来求出 border 的数量 \(cnt_i\),再考虑不交的怎么快速做.

首先这个题要从 kmp 考虑,因为 kmp 求的是每个前缀最长 border. 跳 fail 的本质是遍历前缀的最长 border,即可以遍历所有 border. 所以 kmp 过程中每次前缀 \(i\) 找到的最长匹配位置 \(j\),意味着此时前缀 \(i\) border 数量相比于前缀 \(j\) 增加了 \(1\). 所以我们就可以在递推过程中求出所有前缀的 border 数量 \(cnt_i\)(不考虑是否重叠).

仍然采用 kmp 匹配模式串的思路,考虑先匹配上最长 border 再跳 border,直到第一次跳到 \(2\times j \le i\) 此时的 \(cnt_j\) 就是 \(num_i\).

时间复杂度分析与上一个题类似,可以得出是 \(O(n)\) 的.

P4287 [SHOI2011] 双倍回文

Hint:长度为 \(n\) 的字符串的本质不同回文子串个数是 \(O(n)\) 的.

先用 manacher 求出每个位置的最大回文半径. 由于分成左右两个回文子串,所以我们直接从大到小枚举左回文的中心,利用左边已经求过的最大回文半径来 \(O(1)\) 判断是否合法. 由于左右两边关于 \(i\) 对称,所以左边一旦合法就一定是当前位置最长的双回文串,更新答案之后可以 break 来剪枝.

posted @ 2025-07-25 14:33  Ydoc770  阅读(12)  评论(0)    收藏  举报