Loading

邻项交换的应用 & 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 中。总之,邻项交换不止可以用来单独贪心。

posted @ 2026-08-17 17:59  Trent900  阅读(26)  评论(1)    收藏  举报