字符串问题

Xenia and String Problem

考虑由于好串的定义,导致长度一定为 \(2^i-1\),所以总数是 \(O(n\log n)\) 的,考虑像构建 st 表一样求出所有好串。

修改一个字符看做先删再加,删会导致所有包含这个字符的好串无效,加的贡献分为三种情况。

  1. 左右合法且相等,中间字符出现次数过多。

  2. 左右合法,但是不相等,发现只有左右的中心不同才可能有贡献,检验可以看左右 lcp 长度是否符合条件。

  3. 左右有一个不合法,修改后可以相等,考虑左右的是否仅在那一个点出不同,可以求 lcp 检验。

答案就是不变的 ans 加上最多能使 ans 增加多少。

求 lcp 可以 SA 预处理,总复杂度 \(O(n\log n)\)

Bosco and Particle

一个对撞机可以取它的最小循环节代替,每个对撞机是独立的,所以对于每个对撞机先求出向左和向右的次数的比值 \(\frac{a_i}{b_i}\),并且找到最右的有用的对撞机,设一个空隙被经过的次数是 \(f_i\),则 \(\frac{f_{i-1}}{f_i}=\frac{a_i}{b_i}\)

因为 \(f_i\) 都是整数,所以以 \(f_0\) 为主元,得到最小的合法 \(f_0\),递推出其它 \(f_i\),加起来乘二得到答案。

Fedya the Potter Strikes Back

对于每一个新加的字符,算出包含它的 border 的贡献,加上原来的即可。

求 border 用 kmp,由于每次最多加入 \(1\) 个 border,所以总数是 \(O(n)\),接下来考虑如何快速定位需要删去的 border。

一个 border 会被删去当且仅当它前半部分后面的字符不等于 \(c\),所以记录 \(top_i\) 表示第 \(i\) 个 border 前第一个与它下一个字符不同的 border 是第几个,均摊 \(O(n)\)

border 的贡献是区间 \(w_i\) 最小值,所以用单调栈维护,每次将剩余贡献大于 \(w_i\) 的 border 贡献调整,因为一次会合并所有贡献大于 \(w_i\) 的数,所以用 map 维护均摊 \(O(n\log n)\),删 border 的时候要记得在 map 中减去。

答案可能爆 long long,分成两部分存储即可。

Twilight and Ancient Scroll

将每一类字符串排序后,有一个显然的前缀和优化 dp 做法,因为需要比较两个不同类的字符串的大小,所以用一个指针扫,字符串哈希和二分,判断大小。

同类串排序的方法参照 [SNOI2019]字符串

The Sum of Good Numbers

我们知道一定有一个数的位数大于等于 \(|m|-1\),所以分三种情况。

  1. 两个数位数都是 \(|m|-1\),直接扔到 ans 里。

  2. 前一个是 \(|m|\),可以找前一个与 m 的 lcp,后一个的长度也就确定了。

  3. 后一个是 \(|m|\) 同理。

拿出 ans 中每个三元组进行 check,可以用哈希,因为是 CF 题,所以七重模数大哈希就行了。

Reverses

\(a,b\) 交叉串连得到 \(c\),发现相当于将 \(c\) 划分为偶数回文串的最小贡献。

建出 PAM,回文串长度为 \(2\) 的时候特判,对于每个等差链上维护最佳转移点,转移时暴力跳链,复杂度 \(O(n\log n)\)

Palindrome Addicts

离线,转换为区间查询本质不同回文串,原题是 Loj6070

每一个新的回文串会对前面一段区间有贡献,然后发现一条等差链上的串的贡献形成了一段区间,需要用线段树找左端点,发复杂度 \(O(n\log^2 n)\)

原题因为强制在线,所以用的是主席树,这里可以改为树状数组,但是发现查询的左端点单调向右,所以可以换一个指针扫。

虽然仍是 \(O(n\log^2 n)\),但是现在能过了。

Boboniu and Banknote Collection

每次遇到一个 \(A\overline{A}A\) 就合并成一个 \(A\) 一定不劣,于是最后剩下一个不含有 \(A\overline{A}A\) 的串,预处理折前缀能折多少次,然后暴力折后缀,复杂度 \(O(n\log n+n\sqrt n)\)

posted @ 2023-06-12 16:43  mikefeng  阅读(32)  评论(0)    收藏  举报