leetcode 周赛 505,54名

作者: | 更新日期:

WQS二分算法、Alien Trick、拉格朗日松弛

本文首发于公众号:天空的代码世界,微信号:tiankonguse

零、背景

这次比赛最后一题比较难,涉及到WQS二分算法(又名Alien Trick 或 拉格朗日松弛),触发我的知识盲区了。
网上找了模版,现场调试,最终也没调试通过,遗憾。

本场题型概览如下。
A 题:枚举。
B 题:二进制枚举。
C 题:二维DP+单调队列或线段树优化。
D 题:一维DP+WQS二分优化。

一、区间内的兼容数字之和 I

题意:问数字 n 左右距离 k 之内的数字,哪些数字与 n 的与运算结果为0。
求所有满足条件数字的和。
数据范围:k 小于 100

思路:枚举

k 不大于 100,枚举左右 200 个数字,判断哪些满足要求即可。

二、成本限制的有效二进制字符串

题意:给一个数字 n 和 k,求长度为 n 的二进制满足 1 的个数不超过 k 且不存在连续的 1。
数据范围:n 不大于 12

思路:二进制枚举

n 不大于 12,二进制个数不超过 2^12 个,dfs 枚举所有合法的二进制即可。

三、非重叠子数组最大和 I

题意:给一个数组,至多选择 m 个不重叠的子数组,且子数组长度在 [l,r] 之间,问选择子数组的最大总和是多少。
数据范围:n 不大于 1000

思路:二维DP+单调队列优化

很容易写出一个状态转移方程。

状态:f(i,k) 前 i 个元素至多选择 k 个子数组的最大和。

状态转移方程:

  f(i,k)
= max(f(j, k-1) + pre(i) - pre(j))
= max(f(j, k-1) - pre(j)) + pre(i)
l < i - j < r

观察状态转移方程,max 的值与 i 无关,只与每个位置自身有关系,然后求区间最大值。

最简单的方法是使用线段树,直接求区间最值即可。
复杂度:O(n^2 log(n))

随着 i 的增大,考虑到这个区间也在向右增大,故可以使用滑动窗口来做这道题。
显然,窗口内,如果左边的值比右边的小,则左边的值显然不可能是最优答案。
故只需要维护一个单调递减的滑动窗口即可。
复杂度:O(n^2)

四、非重叠子数组最大和 II

题意:给一个数组,至多选择 m 个不重叠的子数组,且子数组长度在 [l,r] 之间,问选择子数组的最大总和是多少。
数据范围:n 不大于 10^5

思路:WQS二分算法、Alien Trick、拉格朗日松弛

题目与第三题一模一样,只是数据范围变大了。

由于数据范围太大,状态转移方程必须去掉 m 才行。

如果去掉限制 m,类似于 01背包转化为完全背包,可以重复选择了。

状态:f(i) 前 i 个元素选择任意子数组的最大和以及个数。

状态转移方程:

  f(i)
= max(f(j) + pre(i) - pre(j))
= max(f(j) - pre(j)) + pre(i)
l < i - j < r

此时复杂度降低为 O(n)
状态转移方程顺便记录选择的个数,假设为 M。

如果在不加个数限制的情况下,假设最优答案为 M。

如果 M 等于 0,则说明答案为负数,此时无奈只能选择 1 个了。
直接使用类似于 01 背包,只选一个的 O(n) 算法来求最优值。

如果 M 不大于 m,则显然这个就是答案。

如果 M 大于 m,则说明数组中穿插着很多大负数,通过拆分更多的小数组,规避掉大负数,从而得到更大的和。
这个也说明,M 从 1 到 M 之间,拆分的数组越多,答案越大,在之后就答案越小,这显然是一个上凸函数,且 M 是最值分割点。

截图

上凸函数的斜率是递减的,故我们可以构造一个新的函数。

F(i) = f(i) - M*λ

其中 M 为 F(i) 最优值选择的子分组个数, λ 是斜率。

如下图,确定 λ 后,就可以自动贪心求出最优的 M。
而且 λ 与 M 是成正比的,即存在单调性。

截图

因此,可以二分 λ,找到 M=m 时的 λ。

F(i) 求出来了,M*λ 也有了,f(i)就也算出来了。

复杂度:O(n log(n))

这个算法国内称为 WQS二分算法,国外称为 Alien Trick,理论知识是拉格朗日松弛。
关于怎么证明新函数的最优值就是旧函数的最优值,证明方法比较复杂,这里就不介绍了。

五、最后

这次比赛最后一题比较难,属于 IOI 难度的了,后面有机会再深入研究下这个算法。

《完》

-EOF-

本文公众号:天空的代码世界
个人微信号:tiankonguse
公众号 ID:tiankonguse-code

本文首发于公众号:天空的代码世界,微信号:tiankonguse
如果你想留言,可以在微信里面关注公众号进行留言。

关注公众号,接收最新消息

tiankonguse +
穿越