2025.2.14 闲话:二段性贪心单调队列

题目:P5665 [CSP-S2019] 划分,题意不重要,简化一下直接上方程:

\[f_i = \max j \quad\text{s.t.}\quad j<i, b_j \le a_i \]

保证 \(a_i\) 单调递增。

人话:找左边最近的使 \(b_j \le a_i\)\(j\),要求均摊 \(O(1)\)


错误想法:单调栈

关键词:“最近的”,尝试使用单调栈,然后被 Hack 了:

a: 3 4 5
b: 1 6 2

先来通过一个单调栈例题看一下单调栈的工作方式和贪心策略:

找左边最近的使得 \(a_j<a_i\)\(j\)

单调栈在此的贪心策略为:如果 \(j<i\)\(a_j \ge a_i\),那么 \(i\) 永远比 \(j\) 更优,可以用反证法:

假设存在 \(j<i<k\),且 \(j\) 是距离 \(k\) 最近的使 \(a_j<a_k\) 的点。因为 \(a_i \le a_j\),所以 \(a_i<a_k\)。又因为 \(i\) 距离 \(k\) 更近,所以 \(i\) 才应该是满足条件最近的点,与假设矛盾,故 \(j\) 不可能在后面成为答案。

现在模仿这个反证法来反推这个结论如何修改才能对本题适用:

假设存在 \(j<i<k\),且 \(j\) 是距离 \(k\) 最近的使得 \(b_j \le a_k\) 的点。我们需要一些条件来推出 \(b_i \le a_k\) 才能推出矛盾,但是 \(b_j \le a_k\)\(b_i \le a_k\) 显然不能只用 \(i\)\(j\) 之间的关系连接起来。因此,这道题没有单调栈可以用的贪心策略。

所以这道题用不了单调栈,我打了个假算法。


正确做法:单调队列

曾经我以为单调队列维护的只能是移动区间最值问题,但是这道题颠覆了我的想法。

这应该算是一种新型单调队列,具有以下特点

  1. 单调队列需要通过某种贪心的思想,排除掉一定不是最优答案的选项(这个和普通单调队列是一样的)。
  2. 单调队列内存储的元素可以不是合法元素(但要求计入答案的时候合法),而是将来有潜力成为答案的元素
  3. 队内元素从头到尾依次更优(单调性)。
  4. \(i\) 确定的时候,合法答案聚集于队头一边,非法答案聚集于队尾一边
  5. \(i\) 合法的答案对 \(i+1\) 也合法,这样可以保证不会误弹出队首。
  6. 最优元素是最后一个合法的元素

与普通单调队列相比,贪心排除答案、队内元素均有潜力、元素单调性是相同的;不同的是这种单调队列不再要求队内元素均合法(2),而是要求合法答案具有单调性(5)和二段性(4)。

同时它所求解的问题(6)也和普通单调队列有所不同:找最后一个合法元素。这里它所求解的问题更类似于二分查找所求解的问题,不过如果有了随着 \(i\) 右移,答案点(合法区间)单调不降的特征,那么就可以用这种新型单调队列省去一个 \(\log\) 的复杂度。

posted @ 2025-03-06 15:53  Jerrycyx  阅读(8)  评论(0)    收藏  举报