省选集训-字符串杂题

省选集训-字符串杂题

基础子串结构太ex就不看了

CF1827C

考虑如何将一个由若干偶回文串拼接而成的串分解开。

容易发现每次从后往前删掉最短回文串就是对的。

所以问题变成求 li 表示 [li,i] 是以 i 为结尾的最短回文串位置。

则可以 dp 计算,dpi=dpli1+1ans=dpi

l 可以使用 manacher 然后做区间染色得到。

CF1913F

屑题。

考虑计算出 cx 表示改变 ax 后消失的回文串数量,wi,x 表示将 ai 改为 x 后新增的回文串数量即可计算出答案。

考虑使用 manacher 求出原本的各个回文中心以及回文半径,将其往外扩张一个单位后(这个位置失配)再使用哈希求出最长长度,就可以对 w 进行计算了。

以及 c 的计算事实上根据回文半径可以变成区间加等差数列。

考虑求出 c 的二阶差分,然后计算即可。

区间加等差数列别推错了,就尴尬了。

P10716

注意到 A 是该前缀的 border,并且 B 可以为空。

那么找到最长的 border 后,这个串的 border 个数即为所求。

考虑失配树(nxt 树),也即 (i,k) 的询问是找到 i 合法的最近祖先。

可以倍增,问题变为如何判断。

注意到调和级数求和,因此对于每个前缀 [1,i],都预处理出 k=1ni 的最短前缀长度(可能没这么多次)。

那么就只剩下一个判断了。

找的话,pos 后的下一次出现位置可以变成子树内大于某个值的最小编号寻找,失配树上线段树合并即可。

P11150

关于讲课ppt是错的这件事。

要最小化原串的字典序,那么首先就要找到改后第一个与原串不同的位置 np,让这个位置尽量小。

可以对原串建立一个SAM,然后将 B 在 SAM 上逐位匹配(相当于枚举 np 这个位置由 B 的哪一个位置做出贡献)

那么首先就要求了 np 最小。在 np 相同时,我们再哈希判断两个不同的 B 接入位置谁更优。

这样我们就找到了一个最优的接入位置 r,考虑将其变为最小的接入位置。

稍加画图可以发现,对于效果相同的接入位置,那么一定是原串匹配上了 B 的循环节。

所以倍增往前跳的循环节个数,然后哈希求出新的方案里得到的新串哈希值是否与原本串相同即可。

CF1975G

首先做一些讨论:

  1. s,t 不含 ,可以直接判断
  2. s,t 都含 ,将第一个 前面的以及最后一个 后面的位置进行匹配判断,判断通过显然有解。
  3. s,t 仅有一个含 ,类似 2. 先去掉第一个 以及最后一个 前/后面的串。

那么一般地,可以看作 s=s1s2smt 不含 进行匹配。

贪心地,我们动态维护 p,逐个将 sit[p,n] 进行匹配,并将 p 置为第一个匹配到的位置之后(也就是逐个匹配)

考虑到单次匹配代价太大,需要将单次匹配复杂度降至 |si| 级别。

很厉害的地方是将 t[p,p+2|s|) 拿出来匹配,不管有没有匹配位置,p 至少增加 |s|

然后就考虑 |s| 级别复杂度匹配,关于带通配符的字符串匹配,可以考虑 NTT,也就是将每个字符赋权 wi,通配符为 0,计算:

fi=k=0|s|1sktp+i+k(sktp+ik)2

这可以拆为三次差卷积计算。

P11291

注意到 R 可以为空,所以固定 (l,r)k 是一段区间,固定 (l,k)r 也是一段区间。

但是性质更好的是固定 (l,k),不妨设 fl,k 为其对应的最大 r,设 ri 为最大的满足 [i,ri] 是好串的值。

则显然 fl,k=maxijfl,k1(rj)=maxijrifj+1,k1,fl,1=rl

但是注意到最远的,那么一定 r 所有的都不为空,那么对于最右侧的形式,以 k=3 为例,有:

fl,3=maxijri+1fj,2=maxijrimaxjkrj+1rk

而注意到对于跳跃方案:ljk 每一步都应当是最优化的。

形式地说,设 toimaxijri+1rj 取到最优的 jfl,2 转移时用了 tolfl,3 转移时在 [l,fl,2+1] 里找一个 to 最大的转移,而这个位置显然不会低于 tolf 单调不降),因此就变成了 tolf2 转移,也就是找到的位置是 totol

因此就变成了跳 to 的问题,建 to 树,就变成了树上统计的问题。

对于问题一是好做的,相当于只需要 dfs 时维护一个链和,而问题二也可以变成若干区间加等差数列,可以二阶差分解决。

CF1975H

考虑到如果我们要让最大子串最小,那么设 z 是最大字符,重排后一定形如 z+s1+z+s2++sm+z 的形式。

最大子串一定是一个后缀,这是显然的。

因此这相当于是确定下了后缀的最后面是一个 z,然后我们继续将 z+si 视作一个字符,变成了子问题。

所以当最大字符数小于等于其余字符数的时候,我们找到了一个让问题规模减半的方法。

si 应当如何划分?注意到按目前顺序,也自然有 s 的字典序不降的说法,且每个 s 的第一个字符应当组成原本其余字符排序后的一个前缀。

事实上,考虑这样一个贪心:

维护 i,p,初始化为 都为 1,设其余字符排序后是 a,那么我们每次将 [p,m]s 按顺序加上 ai,ai+1,ai+2,这样填完了一轮之后再将 p 变成当前末尾最大的 s 的首次出现为止(也即 sp1<sp=sp+1==sm

这样做显然是对的,我们保证了前面尽可能小,且后续越往后越大,且“变大量”更小。

那么在最大字符数大于其余字符数后怎么办?事实上可以采用同样的处理办法,但是我们要预处理处理结果(保证复杂度)

这个处理结果相当于每个其余字符前面多了相同数量且最多个 z,同时还空余出了若干个 z 作为余下的最大字符,然后末尾也都出了这么多个 z

保证每次递归问题规模减半,问题解决。

CF2053G

考虑单次操作的过程,不妨设长串为 s1,短串为 s0

s0,s1 都可以表达为一个串 t 重复至少一次得到,则可以通过 KMP 求出原串的最小循环节直接判断。

那么就只需要处理 s0,s1 无共同循环节的情况了。

不妨设 s1=s0k+c,且 k 最大,也即 s0 不是 c 的前缀,我们先不断贪心匹配短串,当短串失配时,再撤回若干次匹配,换用长串匹配。

显然,我们至少需要撤回 k 次短串匹配,然后尝试用长串匹配。

同时,我们声称,我们至多需要撤回 k+1 次。

  1. 当撤回 k+1 次可以匹配,说明 cs0 的真前缀。

  2. 如果撤回 k+2 次可以匹配,则撤回 k+1 次也可以匹配(这是显然的)

    那么这就说明 s1+s0=s0+s1,也就说明 cs0,s1 的循环节,与 s0,s1 无共同循环节不符。

  3. 同理撤回更多次的情况也是一样的。

同时,如果撤回 k 次与撤回 k+1 次都可以匹配,我们优先撤回 k 次,因为产生差异只能是撤回用 s1 后连用 s1 进行匹配,也就是撤回后后面的串被匹配为 s1+s1,如果撤回 k+1 这样做遇上这种情况就被封死了(会连续撤回),而撤回 k 就不会出现这种情况,并且如果也被封死,撤回 k+1 次的决策也会寄。

那么我们每次跳跃都是 |s0| 的,总复杂度单 log,而长串的匹配由于 |s1|n2,因此总匹配次数是 O(mn·n)=O(m) 的。

posted @   spdarkle  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示