邻项交换的应用 & P15699 [2018 KAIST RUN Spring] Touch The Sky 解题报告
问题如下:
现在有 \(n\) 个事件,事件 \(i\) 的最晚开始时刻为 \(L_i\),需要花费 \(D_i\) 时间来完成。
问最多可以完成多少个事件?(\(N \le 2.5 \cdot 10^5\))。
考虑将【最早开始时刻】改为【最晚开始时刻】,这是好做的。因为我们会反悔贪心。按照 \(L_i\) 递增排序,然后从前往后扫一遍,将事件放进去。如果目前总时间超出了 \(L_i\),找到完成过的时长最久的事件撤销即可。拿个堆维护。
但是这题里,\(L_i\) 是开始时间,上述方法其实是错的,也没有办法完全搬过来。显然,我们可以 \(L_i \leftarrow L_i + D_i\),但是这种思路是经过上述提示的。我们需要更自然的思路。
我们引出如下模型:邻项交换确定顺序,反悔贪心确定集合。
首先考虑,如果选取的事件集合已经确定,怎么排序可以让成功的可能性最大?
考虑对于两个相邻的被选取的事件 \(i\),\(j\)。在最优顺序下,顺序 \(i \to j\) 一定成功,反之却不一定。于是,假如进行 \(i\),\(j\) 前时间为 \(T\),我们有:\(T \le L_i, T + D_i \le L_j\) 并且 \(T + D_j > L_i\)。消去 \(T\),我们就有 \(L_i + D_i < L_j + D_j\)。这就是排序的关键字了,也符合我们刚刚的提示后的思路。
同理,这种交换的思路也可以用在 DP 中。总之,邻项交换不止可以用来单独贪心。

浙公网安备 33010602011771号