南外集训 2024.1.15 T3
纯粹技术性的题目。
给定一个字符串的后缀数组以及对应的 height 数组的一部分(即一些 height 数组的位置是未知的,用 \(-1\) 表示),要求还原出一种可能的字符串。保证存在一种由 \(26\) 个小写英文字母构成的解。
\(1\le n\le 10^6\)
首先考虑没有 \(-1\) 的情况。注意到此时我们给出了一些位置的相等关系,以及一些等价类的大小关系。注意到大小关系限制只有 \(\Theta(n)\) 个,只要求出等价类以后在 DAG 上 DP 即可。现在的问题是求出字符等价类。根据 SA 数组的定义,可以发现所有字符等价类都是 SA 数组上的连续段(这里 SA 数组上的特定位置对应该位置所代表的后缀的第一个字符)所以我们只关心相邻的两个字符是不是相等,显然相等 \(\iff height_i > 0\)。
现在加入 \(-1\)。如果 \(rk_{sa_{i-1} + 1} < rk_{sa_{i}+1}\),那么 \(s_{sa_{i-1}}\le s_{sa_{i}}\),否则 \(s_{sa_{i-1}} < s_{sa_{i}}\),这里和上面区别不大,但是一个问题是对于一些位置我们不再能通过 \(height_i > 0\) 来判断前后两个字符是不是相等了,所以我们需要用到 \(\forall i, \forall j\in [0, height_i), s_{sa_{i-1}+j} = s_{sa_{i}+j}\)。注意到由于连续段的性质,我们实际上不是合并了 \(sa_{i-1}+j\) 和 \(sa_i+j\),而是把 SA 数组上 \([rk_{sa_{i-1}+j}, rk_{sa_{i}+j})\) 这个区间内所有位置全部和下一个位置合并了。考虑记录一个位置是不是和下一个位置相等,实际上就是这个位置被覆盖次数是不是 \(>0\),所以直接用差分。那么我们要做的是对所有 \(j\in [0, height_i)\), 给 \(d_{rk_{sa_{i-1}+j}}\) 加 \(1\),给 \(d_{rk_{sa_{i}+j}}\) 减一。这个又可以直接重标号一下做离线区间加,直接差分解决。时间复杂度线性。