2025.2.14 闲话:二段性贪心单调队列
题目:P5665 [CSP-S2019] 划分,题意不重要,简化一下直接上方程:
保证 \(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\) 之间的关系连接起来。因此,这道题没有单调栈可以用的贪心策略。
所以这道题用不了单调栈,我打了个假算法。
正确做法:单调队列
曾经我以为单调队列维护的只能是移动区间最值问题,但是这道题颠覆了我的想法。
这应该算是一种新型单调队列,具有以下特点
- 单调队列需要通过某种贪心的思想,排除掉一定不是最优答案的选项(这个和普通单调队列是一样的)。
- 单调队列内存储的元素可以不是合法元素(但要求计入答案的时候合法),而是将来有潜力成为答案的元素。
- 队内元素从头到尾依次更优(单调性)。
- 当 \(i\) 确定的时候,合法答案聚集于队头一边,非法答案聚集于队尾一边。
- 对 \(i\) 合法的答案对 \(i+1\) 也合法,这样可以保证不会误弹出队首。
- 最优元素是最后一个合法的元素
与普通单调队列相比,贪心排除答案、队内元素均有潜力、元素单调性是相同的;不同的是这种单调队列不再要求队内元素均合法(2),而是要求合法答案具有单调性(5)和二段性(4)。
同时它所求解的问题(6)也和普通单调队列有所不同:找最后一个合法元素。这里它所求解的问题更类似于二分查找所求解的问题,不过如果有了随着 \(i\) 右移,答案点(合法区间)单调不降的特征,那么就可以用这种新型单调队列省去一个 \(\log\) 的复杂度。
本文采用 「CC-BY-NC 4.0」 创作共享协议,转载请注明作者及出处,禁止商业使用。
作者:Jerrycyx,原文链接:https://www.cnblogs.com/jerrycyx/p/18755376

浙公网安备 33010602011771号