WQS二分
之前一直觉得这个算法没啥实际用处,现在才知道是我错了
推荐一下这位大佬的博客,让我很好理解了 WQS 二分
这类二分通常用来解决这类问题:
\(n\) 个数,要求恰好选 \(m\) 个,问最大/小和
而这类二分也有一些比较严苛的条件要求:
令 \(g_i\) 为恰好选 \(i\) 个数的最优方案,那么必须有:对于 \(i\in [1, n]\),它们按顺序连接出来的图形是一个凸壳
而且一般来说,如果不限制选的个数,最优解很容易求出(如在线性时间内)
现在假设我们已经知道 \((i, g_i)\) 组成的是一个上凸壳
我们可以对斜率 \(k\) 进行二分,每个斜率会对应一个切点
假设我们可以快速计算出一个 \(k\) 对应的最优选择个数 \(x\),那么如果 \(x<mid\),我们就 \(l = mid + 1\);反之 \(r = mid - 1\)
我们考虑怎么算出这个 \(x\):
-
我们知道,一个直线的表达式是 \(y = kx + b\)
-
由于是上凸壳,当我们用直线去切每个点时,最优点的 \(b\) 一定最大
-
考虑转化式子为 \(b = g_x - kx\),由于 \(b\) 是最大,其实我们可以看做将每个数都减去一个 \(k\),然后直接跑无限制的最优解。这个最优解就是要求的 \(b\),而选择的个数就是要求的 \(x\)
Q & A
- 二分的 \(l\), \(r\) 的初始值怎么选
- 具体分析凸包的形状,观察斜率可能的最大最小值
- 需要小数二分吗
- 不需要,每个 \(x\) 一定有切它的斜率 \(k\)
- 为什么会出现当 \(mid\) 算出来的个数 \(< m\),但 \(mid + 1\) 的个数却 \(> m\)
- 借用上面提到的大佬的图:
可以看到,当 \(x=4,5\) 时,它们被夹在中间,算出的最优选择个数就不会出现它们
因此我们在二分时需要在沿途记录最优答案,一般是在得到的 \(x>=m\) 时记录
P2619 [国家集训队]Tree I
经典例题
权值只对白边改动
注意,当出现白边和黑边的权值相同时,先选白色还是黑色会导致二分是使用 \(x\ge need\) 还是 \(x\le need\)
感性理解就是尽量让白边靠前,这样需要就取,不需要就直接略过,主动权在自己手上
P4983 忘情
化一下式子,原始就等于:
这是一个经典的斜率优化
但直接做是 \(O(nm)\) 的
考虑用 WQS 二分,去掉 \(m\) 这一维,直接跑无限制的 DP
CF125E MST Company
在原先的 WQS 二分的基础上,要判断无解和输出方案
(听说构造方案一直是 WQS 二分的难点)
可以详见这位大佬的博客
我是模仿 leap_frog 靠 sort 的随机性以及 CF 的水数据糊过去的