后缀数组好题选讲

CodeForces 616F Expensive Strings

https://codeforces.com/problemset/problem/616/F

Problem tags

  • string suffix structures
  • strings
  • *2700

Problem Statement

给定 \(n\) 个字符串 \(t_1, t_2, \dots, t_n\)。每个字符串有一个权值,对于 \(1 \leq i \leq n\),有 \(t_i\) 的权值为 \(c_i\)。定义一个字符串 \(s\) 的价值为:

\[f(s) = |s|\sum_{i = 1}^{n}c_i \times appear(t_i, s) \]

其中 \(|s|\) 表示 \(s\) 的长度,\(appear(t_i, s)\) 表示 \(s\)\(t_i\) 中作为子串出现的次数。

\(f(s)\) 的最大值,要求 \(|s| > 0\)

Constraints

  • \(1 \leq n \leq 10^5\)
  • \(\displaystyle \sum_{i = 1}^{n}|t_i| \leq 5 \times 10^5\)
  • \(\displaystyle \sum_{i = 1}^{n}\sum_{j = 1}^{|t_i|}[t_{i, j} \in \{\text{a, b, c, }\dots\text{, z}\}] = \sum_{i = 1}^{n}|t_i|\)
  • \(-10^7 \leq c_i \leq 10^7\)

Solution & Code

考虑把 \(t_1, t_2, \dots, t_n\) 拼成一个大字符串 \(T\),用 互不相同 的分隔符分开(分隔符不能是小写字母)并建立后缀数组。

考虑统计 \(s\)\(t_1, t_2, \dots, t_n\) 中作为子串的所有出现。发现只需要统计 \(s\)\(T\) 中的所有作为子串的出现即可。考虑统计 \(|s| = k\) 的答案,我们只需要 \(\text{LCP}(T[x \sim |T|], T[y \sim |T|]) \geq k\),发现需要的是 \(\displaystyle \min_{\min(rk_x, rk_y) + 1}^{\max(rk_x, rk_y)}height_i \geq k\),也就是对于所有的 \(\min(rk_x, rk_y) < i \leq \max(rk_x, rk_y)\),有 \(height_i \geq k\),考虑建图,如果 \(height_u \geq k\),那么就在 \(u - 1\)\(u\) 之间连一条边,意思就是 \(rk = u - 1\) 的后缀和 \(rk = u\) 的后缀的 \(\text{LCP}\geq k\)。所以 \(\text{LCP}(T[x \sim |T|], T[y \sim |T|]) \geq k\) 当且仅当 \(rk_x\)\(rk_y\) 在图中连通,一个连通块内的拥有一个长度为 \(k\)\(\text{LCP}\),只需要用并查集维护权值即可,然后更新答案。至于具体如何建图,只需要倒序枚举 \(\text{LCP}\) 的长度,然后按 \(height\) 数组的具体值建图即可,具体见代码。记得答案对 \(f(t_1), f(t_2), \dots, f(t_n), f(\text{a}), f(\text{b}), \dots, f(\text{z})\) 取个 max,时间复杂度瓶颈在建立后缀数组/dx,为 \(O(n \log^2 n)\)

Warning:答案的下界为 \(0\),你可以构造一个足够大的字符串然后不在任何一个字符串内作为子串出现!!!

代码:https://codeforces.com/contest/616/submission/244267521

posted @ 2024-01-31 22:11  CountingGroup  阅读(10)  评论(0编辑  收藏  举报