GYM102412J Yet Another Mex Problem 解题记录

题意:

给定序列 \(a\),一个常数 \(k\)

记一个区间 \([l,r]\) 的贡献为 \(\text{mex}(a_l,\cdots,a_r)\times (\sum_{i=l}^r a_i)\)

你需要把 \(a\) 划分为若干个大小不超过 \(k\) 的区间,最大化贡献和。

\(1 \le n \le 2\times 10^5\)


\(dp_x\) 表示以 \(x\) 作为结尾的最大贡献,\(S_x\) 表示前缀和。

有如下的转移:

\[dp_x = \max_{x-k \le i < x}\{dp_i+\text{mex}(a_i+1,\cdots,a_x)\times (S_x-S_i) \} \]

我们考虑对右端点 \(r\) 维护每个左端点 \(l\)\(\text{mex}\) 值。

只需对于每个 \(\text{mex}\) 相同的 \(l\) 段分别计算答案。


首先来考虑如何维护 \(\text{mex}\),首先显然对于固定的右端点 \(r\)\(\text{mex}(a_l,\cdots,a_r)\) 是有单调性的。

而插入一个数字 \(x\) 后,所有 \(\text{mex}\)\(x\) 的位置都会发生改变。

我们只需要每次对这个段里,一段 \(\text{mex}\) 相同的位置一起处理,均摊下复杂度就是正确的。

可以简单的用线段树二分处理。现在来讨论如何计算贡献。


我们知道一个点 \(l\) 的贡献可以看成 \(dp_{l}-S_l\times \text{mex}\)

对于 \(\text{mex}\) 相同的段,只需求出 \(dp_{l}-S_l\times \text{mex}\) 的最大值。

那么查询一段 \(\text{mex}\) 相同的区间的答案,只需线段树维护凸包即可。均摊 \(O(n\log n)\)

对于每个段,它的贡献是关于 \(S_r\) 的一次函数,因此也可以用线段树维护凸包。

对于 \(k\) 的限制,我们只需每次查询一段后缀的答案,然后手动查询一个段的答案即可。

这样总复杂度 \(O(n\log^2 n)\),可以通过此题。


但是其实有 \(O(n\log n)\) 的做法:

预处理出每个时刻,\(\text{mex}\) 发生改变的区间,均摊是 \(O(n)\) 个。

放在线段树上,当求出某个区间 \([l,r]\) 的所有 \(dp\) 值时,就可以得到这个区间对应的 \(\text{mex}\) 的最值,这可以在 \(O(n\log n)\) 的时间内做到。

类似标记永久化,再使用线段树维护每个区间的凸包,即可均摊 \(O(n\log n)\) 的时间解决此问题。

posted @ 2022-09-21 11:19  一般通过小萌新  阅读(226)  评论(0编辑  收藏  举报