20240904:字符串选做
P4555 [国家集训队] 最长双回文串
题意:给定字符串 \(s\),找到他最长双回文串 \(t\) 的长度。双回文串定义为存在一个 \(i > 1\) 使得 \(t[1, i)\) 和 \(t[i, n]\) 都是回文串。\(\vert s\vert \le 10^5\)。
二分哈希求出所有回文中心的半径,设以 \(i\) 为中心的最长回文串为 \([l_i, r_i]\)。
我们发现当两个回文中心确定时,最长双回文串的长度唯一确定(左边界向左延伸一格必须先使右边界往里缩一格,否则左右两串出现重叠)。
枚举回文中心 \(i\),找到一个最小的 \(j\) 使得 \(r_j \ge l_i - 1\),显然可以树状数组维护,在 \(r_i\) 的位置加入 \(i\)。submission
P3546 [POI2012] PRE-Prefixuffix
题意:定义 \(s\) 和 \(t\) 是循环相同的,当且仅当 \(s\) 能够将一个后缀移到开头使得与 \(t\) 完全相同。
给出字符串 \(s\),找到最大的 \(i \le \frac{n}{2}\) 使得前缀 \(pre_i\) 和后缀 \(suf_i\) 是循环相同的。
枚举 \(s\) 的 border \(i\),再找 \(s[i + 1, n - i]\) 的最长不重叠 border,令 \(s_i = s[i + 1, n - i]\),发现把 \(s_i\) 的 border 掐头去尾就是 \(s_{i + 1}\) 的 border。
反过来讲,有 \(B_{\max}(s_i) \le B_{\max}(s_{i + 1}) + 2\),设 \(p = B_{\max}(s_i)\),当 \(i \to i - 1\) 时,令 \(p \to p + 2\),然后不断减 \(1\) 直到合法,势能分析可以得出是线性的。
更加巧妙的做法:把 \(s\) 重排成 \(s_1s_ns_2s_{n - 1} \cdots\),那么两个 border 就是最靠前的两个相邻回文串(长度皆为偶数),和上题一样维护。
Minimal String Xoration
题意:给定一个长度为 \(2^n\) 的字符串 \(s\),选出一个 \(k \in [0, 2^n)\) 使得满足 \(t_i = s_{i \oplus k}\) 的字符串 \(t\) 的字典序最小,输出 \(t\)。\(n \le 18\)。
\(f(k, i)\) 表示选了 \(k\) 得到字典序最小的 \(t\) 的 \(2^i\) 的前缀,显然有 \(f(k, i) = f(k, i - 1) + f(k \oplus 2^{i - 1}, i - 1)\),+ 表示拼接。
类似后缀数组 \(O(n\log n)\) 构造,求出 \(f(k, i - 1)\) 和 \(f(k \oplus 2^{i - 1}, i - 1)\) 在 \(i - 1\) 时的排名就可以当做两位数排序。
时间复杂度 \(O(n^22^n)\),基数排序可以省掉一个 \(n\)。submission
x-prime Substrings
题意:定义只有数字组成的字符串 \(s\) 是 x-prime 的当且仅当 \(\sum s_i = x\) 且不存在一个子串和是 \(x\) 的真因子(不是他本身)。
给定字符串 \(s\) 和正整数 \(x\),求 \(s\) 至少要删掉多少字符才不存在一个子串是 x-prime 的。\(\vert s\vert\le 1000, x\le 20\)。
注意到 \(x\) 很小,满足 x-prime 的字符串应当也很少,称之为非法子串。
删多少字符才能不存在非法子串的这类问题很容易想到构造 ac 自动机,最坏情况下,所有非法串构成的字典树大小只有 \(S = 4853\)。
\(f(i, s)\) 表示前 \(i\) 个字符匹配到 ac 自动机的状态 s 时需要删多少个才合法,枚举 \(i\) 删不删,时间复杂度 \(O(\vert s\vert S)\)。submission
P7361 「JZOI-1」拜神
题意:给定字符串 \(s\),\(q\) 次询问 \(s[l, r]\) 出现至少两次的最长子串长度。\(n \le 5\times 10^4, q\le 10^5\)。
考虑询问的本质,长度 \(L\) 合法等价于存在 \(i ,j \in [l, r - L + 1]\) 满足 \(\text{lcp}(suf_i, suf_j) \ge L\),可以二分。
后缀排序求出 height 数组,\(h_i = \text{lcp}(suf_{sa_i}, suf_{sa_{i - 1}})\),考虑 \(suf_{sa_i}\) 与 \(suf_{sa_{i - 1}}\) 连边,那么 \(L\) 合法就是加入所有 \(h \ge L\) 之后 \(i, j\) 在同一连通块。
维护 \(nxt_i\) 表示与 \(i\) 在同一连通块的大于 \(i\) 的最小后缀编号,这个东西可以并查集的启发式合并实现,每个连通块开个 set 维护所有编号。
那么长度 \(L\) 到底怎么判断呢?区间查询 \([l, r - L]\) 当中最小的 \(nxt_i\) 是否 \(\le r - L + 1\),显然可以线段树。
你当然可以离线。也可以维护持久化线段树 \(T_i\) 表示加入所有 \(h \ge i\) 后 \(1 \sim n\) 的 \(nxt\) 值,时空复杂度皆为 \(O(n\log^2n)\)。submission
REPEATS - Repeats
题意:求连续出现次数最多的重复子串的连续出现次数,多测。\(T \le 20, n\le 50000\)。
枚举重复子串长度 \(L\),每隔 \(L\) 放置一个关键点 \(L, 2L, 3L\cdots\)(1-base)。
如果一个子串是 k-repeat 的,那么他一定恰好覆盖 \(k\) 个关键点。 这个 \(k\) 显然是可以二分的,考虑怎么 check。
单调队列维护长度为 \(k\) 的窗口内关键点所代表后缀以及前缀的排名,方便通过正串和反串的后缀数组求出 LCP 和 LCS(suffix)。
出现 (k, L) - repeat 当且仅当 \(tor + tol - 1 \ge L\),其中 \(tor\) 表示当前窗口内关键点表示后缀的 LCP。
枚举 \(L\) 填关键点是一个调和级数,直接做是双 log 的。
考虑一个关键点区间 \(p_l, p_{l + 1} \cdots p_r\),如果 \(tor + tol - 1\) 不小于 \(L\),则称 \([l, r]\) 是优秀的。显然如果 \([l, r]\) 是优秀的,任意其子区间也是优秀的。
设 \([l, r]\) 为右段点是 \(r\) 是的极大优秀区间,如果 \([l - 1, r + 1]\) 优秀则 \([l - 1, r]\) 优秀,与 \(l\) 是极小左端点矛盾。因此 \(r \to r + 1\) 时左端点单调不降。
双指针代替二分,时间复杂度 \(O(n\ln n)\)。submission
P5115 Check,Check,Check one two!
题意:给定字符串 \(s\) 以及正整数 \(k_1, k_2\),求:
数据范围:\(k_1, k_2 \le n \le 10^5\)。
由于 \((i, j)\) 对于 lcp 和 lcs 都是相同的,我们把他们接在一起,统计 \(i - \text{lcs} + 1\) 处的 lcp。
如果 \(\text{lcp}(i, j) = L\land s_{i - 1} \ne s_{j - 1}\),那么他对答案有 \(F(L)\) 的贡献,其中:
可以 \(O(n)\) 预处理。
考虑 \(s_{i - 1} \ne s_{j - 1}\) 的限制,否则相同子串不是极长。正难则反,容斥减掉 \(s_{i - 1} = s_{j - 1} = a\sim z\) 的情况。
问题转化为与 \((i, j)\) 的 lcp 相关的一个式子,根据 sa 的经典套路,在 height 数组上单调栈维护 \(\sum_{j < i}[s_{sa_j - 1} = ch] F(\min_{j + 1}^i h)\)。submission
P8147 [JRKSJ R4] Salieri
题意:给定 \(n\) 个串 \(s_i\) 以及其权值 \(v_i\),\(q\) 次询问,每次给出一个文本串 \(t\),设 \(cnt_i\) 表示 \(s_i\) 在 \(t\) 中的出现次数,求 \(cnt_i \times v_i\) 的第 \(k\) 大值。
数据范围:\(\sum \vert s\vert \le 5\times 10^5, n, m \le 10^5, k \le n\)。
把文本串放在原串 ac 自动机上跑,走到一个状态则将其 tag 加一,最终 \(cnt_i\) 等于 \(s_i\) 的终止节点所表示状态在失配树上的子树和。
考虑对所有走过的状态建出虚树,由于一共只走 \(\vert t \vert\) 步,虚树规模也是 \(O(\vert t\vert)\) 的。
不难发现 \(x\) 与其虚树上的父亲 \(fa\) (不含)之间路径的 \(cnt\) 都是一样的,也就是说,我们把整棵失配树划分为 \(O(\vert t\vert)\) 条 \(cnt\) 相同的链。
二分答案 \(mid\),问题转化为有多少结束状态满足 \(v_i \ge \dfrac{mid}{cnt_i}\)(\(cnt = 0\) 趋向正无穷,忽略),树上主席树实现,时间复杂度 \(O(\sum \vert t\vert \log \sum\vert s_i\vert \log V)\)。
String Journey
题意:给定字符串 \(s\),找到最大无交子串集 \(T\) 的大小,满足 \(t_i\) 是 \(t_{i - 1}\) 的真子串(非本身)。
首先,将字符串翻转,限制转化为 \(t_{i - 1}\) 是 \(t_{i}\) 的真子集。
观察1:如果大小 \(k\) 合法,一定存在一组方案解使得 \(\forall \vert t_i\vert = i\)。
由于是真子串,显然有 \(\vert t_i\vert \ge i\)。考虑找到第一个长度大于 \(i\) 的位置,删掉前后缀使之成为 \(i\),不会影响整个方案的合法性。
设 \(f_i = k\) 表示长度为 \(i\) 的前缀,强制使 \(s_i\) 等于 \(t_k\) 的结尾的最大合法长度。
观察2:\((i - 1) - f_{i - 1} + 1\le i - f_i + 1\)。
对于任意 \(i\) 的方案,删掉 \(t_1\) ,删掉 \(t_{i > 1}\) 最后一个字符,能够得到一组 \(i - 1\) 的长度为 \(k - 1\) 的方案。即 \(f_i - 1 \le f_{i - 1}\),与结论等价。
令 \(l = r - f_r + 1\),即前缀 \(r\) 最优方案 \(t_k\) 的左端点。
我们称 \([l, r]\) 合法,当且仅当他是 \(r\) 一组方案的 \(t_k\),注意这里的方案需要满足 \(\vert t_i\vert = i\),不难发现若 \([l, r]\) 合法,则所有 \([l, r]\) 的后缀合法。
根据观察2可知,随着 \(r\) 的增大,\(l\) 单调不降。考虑从 \([l, r - 1]\) 到 \([l, r]\):
\([l, r]\) 合法当且仅当存在一个合法串 \([l^\prime, r^\prime]\) 满足 \(r^\prime < l\) 且与 \([l + 1, r]\) 和 \([l, r - 1]\) 之一相同。
考虑在 SAM 上对于每个状态 \(p\) 维护该状态所有右端点小于 \(l\) 的合法串的最大长度 \(g_p\)。
那么 \([l, r]\) 合法等价于 \([l + 1, r]\) 和 \([l, r - 1]\) 对应的状态中 \(g_p\) 的最大值大于等于 \(r - l\),如果合法则跳过。
否则 \(l \to l + 1\),此时需要更新所有右端点等于 \(l\) 的合法字符串,其中左端点范围是确定的 \([l - f_l + 1, l]\)。
设 \(p\) 表示 \([l - f_l + 1, l]\) 的状态,现将 \(g_p\) 与 \(f_l\) 取 max,然后往上跳 \(p\) 的祖先,如果 \(g_p\) 已经是 \(L(p)\) 了,不需要再往上跳;否则 \(g_p \gets L(p)\)。
时间复杂度均摊 \(O(n)\)。(一共就 \(O(n)\) 个状态,每个状态被更新至多 \(2\) 次)submission
Everybody Lost Somebody
题意:

浙公网安备 33010602011771号