[misc-1]wqs 二分的一种特殊处理方式
通过整数二分实现 wqs 二分时的一个细节是凸壳上存在三点共线的情况。
一种广为人知的处理方案为:我们每次二分时,跑出「分组」方案最多的解,也就是所有切点中横坐标最大的一个;如果这个横坐标大于等于要求的
很遗憾,这种方法并不完美。
- 我们没法求出具体方案,只能求出答案。
- 对于高维情况无法方便处理。
如果我们只想要求出具体方案,对于大多数的问题(DP 过程中凸性仍满足),我们可以采用如下处理:
我们发现 DP 过程中可以转移过来的位置是凸壳上一段连续的区间。维护
这样我们已经可以非常优雅地实现二分了:
while (l <= r) {
auto mid = (l + r) >> 1;
check(mid);
if (L[n] <= k && R[n] >= k) {
ans = mid;
break;
} else if (L[n] > k)
l = mid + 1;
else
r = mid - 1;
}
输出答案时,我们倒着扫一遍,记当前还需要分
il void construct() {
vector<int> sol;
k--;
for (int l = n - 1, r = n; l; l--) {
if (L[l] <= k && R[l] >= k && calc(l, r) + ans == f[r]) { // ans 是斜率
k--, sol.emplace_back(l);
r = l;
}
}
reverse(sol.begin(), sol.end());
cout << "Yes\n";
for (int x : sol)
cout << x << ' ';
}
例题-Gym102268J
注意维护
另外如果只要求答案但是高维还有一种处理方案:对于上凸的函数
直接二分即可。