AT_arc058_d [ARC058F] 文字列大好きいろはちゃん
显然直接做不会优于 \(O(nk^2)\),我们需要对字典序这个东西发掘一些更深的性质。
假设我们考察完 \([1, i]\) 中每个字符串 \(s\),设 \(f_{i, j}\) 为前 \(i\) 个字符串拼出长度为 \(j\) 的字符串最小字典序是多少,容易发现该状态有用当且仅当 \([i + 1, n]\) 能够拼出一个长度为 \(k\) 的字符串,这一点可以背包预处理,这样我们丢掉了一些可能会影响下面过程正确性的状态,剩下的所有状态都是对转移生效的。
我们考察 \(f_{i}\) 的有用 \(j\) 集合 \(S = \{j_1, j_2, ..., j_k\}\),如果对于 \(1 \le p \le q \le k\),\(f_{i, j_p}\) 与 \(f_{i, j_q}\) 不形成前后缀关系,则字典序较大的那一方必然是无用状态,经过这么一步,我们得到精简过后的有用 \(j\) 集合 \(T = \{j_1, j_2, ..., j_l\}\),其中按照从小到大的顺序依次满足前后缀关系,所以我们只需要记录最长的串的长度和有用 \(j\) 集合 \(T\) 即可。 那么现在状态数下调到了 \(O(nk)\)。
接下来考察转移,如果需要转移到 \(i + 1\),则枚举 \(T\) 中每个 \(j\) 尝试往后面插入得到一个字典序更小的字符串(当然,插入后长度得合法才行),显然,此时会保留原来最长的串一个极长合法前缀再拼上 \(s_{i + 1}\),这一步只需要比较字典序大小,貌似可以用 Z 函数和 SA 做,不知道能不能用哈希,应该是可以的。
到这里复杂度就是 \(O(nk)/O(nk \log n)\)。
这个题也不是很简单,需要先想到保留有用状态之后,将必然不会成为最优状态的状态给干掉,全部做法都围绕字典序选前不选后的性质展开。

浙公网安备 33010602011771号