我曾经被 wqs 二分的边界折磨死了。后面听说有种很无脑的写法,听说是 lhx 大神发明的,记录一下。
假设我们要求的是恰好 \(k\) 个的最大值,大概是这样的:
int l = -1e6, r = 1e6;
while (l + 1 < r) {int mid = l + r >> 1;if (check(mid).se >= k) l = mid;else r = mid;
}
return min(check(l).fi + l * k, check(r).fi + r * k);
这个东西很巧妙的地方在于,你不再需要在 check()
里再关心同样结果下是多取还是少取。而且不用再关心 l
是取 mid
还是 mid + 1
的问题了。
好,问题来了,为什么这个是对的?而且这个求的是最大值啊,为什么取 min 是对的?
我们画个图。
假设答案在 Ans 点,我们二分到了 l 在 L,r 在 R,此时我们用 L 算出来的 Ans' 是飞出了答案的凸函数的,而用 R 算出来的是答案。我们发现算出来只可能更大,而且因为是整数所以一定有一个是答案。于是我们取个 min 就好啦。