WQS二分

本博客以一种较为少见的方式来解释WQS二分。

题目

首先,WQS二分用于解决什么问题?

我们先看一个伞兵题目:

有一个 n n n 个数的数组 a a a
求在 a a a 中恰好选择 m m m 个数的情况下,选择的数的和的最大值。

你现在看到了这个题目,你发现你不会排序,不会贪心。好难啊,你想。

你打算用另一种方式解决这题。

做法

我们定义 g ( x ) g(x) g(x) 为恰好选择 x x x 个数的情况下,选择的数的和的最大值。

经过观察,我们发现 g ( x ) g(x) g(x) 是一个凸函数。

g(x)
这表明, g ( x ) g(x) g(x) 只有一个最大值(也就是把所有正数都取了的情况)。

但你取不到,因为他不一定是 m m m

如果我们不考虑 m m m 的限制,肯定会取这个最大值。

那么我们考虑如何做出改变使得不用考虑 m m m 的限制。

考虑给选择数一个惩罚或奖励 k k k,我们每次选择一个数,答案就增加 k k k。(谁告诉你 k k k 不能是负数了)

于是,这个函数 g ( x ) g(x) g(x) 就转变成另一个函数 f ( x ) = g ( x ) + k x f(x) = g(x) + kx f(x)=g(x)+kx 了。

显然,当 k k k 取值增大, f ( x ) f(x) f(x) 的最大值取值位置就往右移动。当 k k k 取值减少, f ( x ) f(x) f(x) 最大值取值位置往左移动。

而我们能够轻而易举的对于每个 k k k 计算 f ( x ) f(x) f(x) 最大值取值位置和 f ( x ) f(x) f(x) 最大值( O ( n ) O(n) O(n))。

  • 由于 f ( x ) f(x) f(x) 是选择 x x x 个时的最大值,那么 f ( x ) f(x) f(x) 的最大值就是选择任意个的最大值,相当于取消了最大值限制。

所以,我们可以二分 k k k,根据当前 k k k f ( x ) f(x) f(x) 最大值取值位置与题目限制 m m m 的大小关系来更改 k k k

最终可以获得最大值取值位置为 m m m 时的 k k k f ( m ) f(m) f(m)

然后通过 f ( x ) = g ( x ) + k x f(x) = g(x) + kx f(x)=g(x)+kx,可以反推出 g ( m ) = f ( m ) − k m g(m) = f(m) - km g(m)=f(m)km

做完了, O ( n log ⁡ n ) O(n\log n) O(nlogn)我们震惊的发现时间复杂度和原做法没区别。

好,想必到这里你大致看懂WQS二分的用法或者大致知道WQS二分时什么东西了。

为了方便理解,我们再来一道题(一道需要用到WQS二分的题目)。

题目

有一张 n n n 个点, m m m 条带权边的图 G G G,每条边权值为 w i w_i wi
求图 G G G 的生成树的最大权值和,满足点 s s s 恰好选择 t t t 条边。

首先发现本题难以使用 d p dp dp 之类算法来做。

其次,本题取消限制后极其容易。

最后,容易发现 ,关于 t t t 的函数 g ( t ) g(t) g(t) 代表选择 t t t 条时的答案,是一个凸函数。

我们就可以使用WPS二分以 O ( log ⁡ n ) O(\log n) O(logn) 的代价换取取消限制。

做法

还是一样,我们取消限制,然后增加奖励或惩罚 k k k

根据取最大值位置与 t t t 的关系,二分惩罚 k k k,直接使用最小生成树 O ( n ) O(n) O(n) 来计算惩罚为 k k k 时最大值。

最终可以得出在一定惩罚下,取 m m m 条边时的最大值。我们只需要减去惩罚即可。

也可以换一种方法理解。

我们将 g ( x ) g(x) g(x) 的图像画出,是一个凸函数。
在这里插入图片描述
我们现在需要求 x = t x=t x=t 时的取值 g ( t ) g(t) g(t)

我们发现对于每个在 g ( x ) g(x) g(x) 上的点 ( x , g ( x ) ) (x, g(x)) (x,g(x)),都存在一个斜率 k k k,使得经过这个点的斜率为 k k k 的直线 l l l 能与 g ( x ) g(x) g(x) 相切。

因为 g ( x ) g(x) g(x) 是一个凸函数,所以随着 x x x 的增大, ( x , g ( x ) ) (x, g(x)) (x,g(x)) 对应斜率 k k k 会随之增大。

所以我们可以通过二分斜率 k k k,来求出 x = t x=t x=t 时的取值 g ( t ) g(t) g(t)

对于每次二分的斜率 k k k,我们要求 g ( x ) g(x) g(x) 中切线斜率为 k k k 的切点。我们设直线 l l l y y y 轴截距为 f ( x ) f(x) f(x),代表斜率为 k k k 的直线 l l l 经过点 ( x , g ( x ) ) (x, g(x)) (x,g(x)) 时的 y y y 轴截距。

g ( x ) = k x + f ( x ) g(x) = kx + f(x) g(x)=kx+f(x)

容易发现,当 f ( x ) f(x) f(x) 取到最大值时, y = k x + f ( x ) y=kx+f(x) y=kx+f(x) 就会与 g ( x ) g(x) g(x) 函数相切,切点则是此时的 ( x , g ( x ) ) (x, g(x)) (x,g(x))

所以我们尝试求出 f ( x ) f(x) f(x) 最大值,从 g ( x ) = k x + f ( x ) g(x) = kx + f(x) g(x)=kx+f(x) 可得 f ( x ) = g ( x ) − k x f(x) = g(x) - kx f(x)=g(x)kx

这个式子可以感性理解为: f ( x ) f(x) f(x) 为将与 s s s 相连的边中所选的 x x x 条边的权值都减少 k k k 时,选择 x x x 条边时的生成树的最大权值和。

所以 f ( x ) f(x) f(x) 中最大值则为:将与 s s s 相连的边中所选的边的权值都减少 k k k 时,最大生成树的权值和。

所以我们可以非常容易的求出 f ( x ) f(x) f(x) 最大值,和取得最大值时选择的边数 x x x

我们就可以开始二分了。

对于最终求出的 f ( t ) f(t) f(t),我们可以根据 g ( x ) = k x + f ( x ) g(x) = kx + f(x) g(x)=kx+f(x),求出 g ( t ) g(t) g(t)

总结

经过上面几题可以发现,WQS二分适用于符合一下几点的问题:

  • 有一个恰好选择的个数限制 m m m
  • 代表恰选 x x x 个时答案的函数 g ( x ) g(x) g(x) 需要为凸函数。
  • 取消限制 k k k 后问题可以快速计算。

解决时,一般选取一个附值 k k k,使得每多选一次,最终答案就增加 k k k。然后计算当附值为 k k k 时的最大值取值位置 x 0 x_0 x0。将其与限制 m m m 像比较。由于函数是凸函数,附值为 k k k 时的取最大值位置 h ( k ) = x 0 h(k) =x_0 h(k)=x0 有单调性。所以可以二分 k k k x 0 x_0 x0 靠近 m m m,最终计算得当附值为 k 0 k_0 k0 是取最大值位置 h ( k 0 ) = m h(k_0)=m h(k0)=m 时。再将附值为 k 0 k_0 k0 时的最大值减去 k × m k\times m k×m 即可。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值