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

  1. 二分的 \(l\), \(r\) 的初始值怎么选
  • 具体分析凸包的形状,观察斜率可能的最大最小值
  1. 需要小数二分吗
  • 不需要,每个 \(x\) 一定有切它的斜率 \(k\)
  1. 为什么会出现当 \(mid\) 算出来的个数 \(< m\),但 \(mid + 1\) 的个数却 \(> m\)
  • 借用上面提到的大佬的图:

可以看到,当 \(x=4,5\) 时,它们被夹在中间,算出的最优选择个数就不会出现它们

因此我们在二分时需要在沿途记录最优答案,一般是在得到的 \(x>=m\) 时记录


P2619 [国家集训队]Tree I

经典例题

权值只对白边改动

注意,当出现白边和黑边的权值相同时,先选白色还是黑色会导致二分是使用 \(x\ge need\) 还是 \(x\le need\)

感性理解就是尽量让白边靠前,这样需要就取,不需要就直接略过,主动权在自己手上

代码


P4983 忘情

化一下式子,原始就等于:

\[(1+\sum_{i=1}^n x_i)^2 \]

这是一个经典的斜率优化

但直接做是 \(O(nm)\)

考虑用 WQS 二分,去掉 \(m\) 这一维,直接跑无限制的 DP

代码


CF125E MST Company

在原先的 WQS 二分的基础上,要判断无解和输出方案

(听说构造方案一直是 WQS 二分的难点)

可以详见这位大佬的博客

我是模仿 leap_frog 靠 sort 的随机性以及 CF 的水数据糊过去的

posted @ 2022-09-18 22:00  zuytong  阅读(31)  评论(0编辑  收藏  举报