P9623 [ICPC2020 Nanjing R] Baby's First Suffix Array Problem

· · 题解

我永远喜欢数据结构

很神仙的串串题,第一次见这种做法。在 CF 上应该能评个 \ge \color{maroon}{*3300}当时场上想假了直接对着这玩意冲成小丑了。百度上只搜到了后缀树的题解,你谷的一篇后缀数组题解可能是因为作者太神仙了所以讲的比较简略,这里来一篇详细一点的后缀数组题解。

长文码字不易,有笔误还请耐心指出 /bx。

题目传送门

  • 给出长度为 n 的字符串 sm 组询问对 s[l,r] 这个子串进行后缀排序后,(这个子串的)后缀 s[k,r] 的排名。排名定义为比它小的后缀的个数 +1

  • 多组数据,记 N=\sum nM=\sum mN,M\le 5\times 10^4

这个 N\le 5\times 10^4\text{5.00\,s} 时限是不是为了放时间复杂度 \mathcal{O}((N+M)\log^3 N) 的做法过啊,是的话就太不牛了 /qd。

先对原串进行后缀排序。

考虑从排名的定义入手,求出子串中有多少个后缀比询问的后缀小。对于这些子串中的后缀,考虑找到它们在原串中的后缀,尝试寻找充要条件。

设有(子串的)后缀 s[i,r],其中 i\in[l,k)\bigcup \,(k,r]。按两类情况考虑。

至此两类统计都解决了。接下来算复杂度。因为有主席树和 ST 表,所以空间复杂度显然为 \mathcal{O}(N\log N)

至于时间复杂度(只说每个部分的瓶颈),后缀排序是 \mathcal{O}(N\log^2 N) 的(因为不是瓶颈所以没用基数排序优化)。rk_i<rk_k 的统计需要往主席树中插入 \mathcal{O}(N) 个点对,并且每次询问要进行一次 \mathcal{O}(1) 检查(ST 表)的二分以及 \mathcal{O}(\log N) 的主席树查询,时间复杂度为 \mathcal{O}((N+M)\log N)

对于分治部分,每个询问会在 \mathcal{O}(\log N) 层分治中被扫到,每次扫到要做一次主席树查询和 vector 二分,单次是 \mathcal{O}(\log N)。每个点对会在 \mathcal{O}(\log N) 层分治中被插入主席树,单次也是 \mathcal{O}(\log N)。这部分的时间复杂度为 \mathcal{O}((N+M)\log^2 N)。为了维护主席树,每层分治需要将点对进行排序,由于每层分治的区间总长度为 N,因此任意一层排序的 \log 不超过 \mathcal{O}(\log N)。容易通过乘法分配律得到是 \mathcal{O}(N\log^2 N) 的。因此,分治部分的总时间复杂度为 \mathcal{O}((N+M)\log ^2 N)

综上,本做法时间复杂度为 \mathcal{O}((N+M)\log^2 N),空间复杂度为 \mathcal{O}(N\log N),可以接受。

代码

AC 记录

完结撒花!