wqs 二分
更应该说是一种思想吧。
我们希望知道恰好选择 \(k\) 个物品时的答案,但世界上哪来的那么多恰好呢。令 \(f_x\) 是恰好选择 \(k\) 个物品时的答案,那么点集 \((x,f_x)\) 常会形成一个凸包,于是要知道特定 \(x\) 的答案,就只需要二分出这个点的斜率,然后用截距加上横坐标乘斜率即可,这个过程就是 wqs 二分,而求最优截距的方法是多样的,下面会说。其中有许多需要注意的细节,比如连着几个值斜率相同(其实没关系,反正最后求出来的答案是一样的)。另外精度也是一个需要考虑的问题。一般用下面这种写法:
while(l<r){
mid=(l+r>>1)+1;solve(mid);
if(g[1].num>=n)ans=g[1].data+n*mid,l=mid;else r=mid-1;
if(g[1].num==n)break;
}
最后出来的 \(ans\) 就是我们想要的。其它的倒是没什么了,具体看题。
Akvizna link 忽略轮数的限制,用 \(f_x\) 代表还剩 \(x\) 个人的最大收益。于是有 \(f_x=\max\limits_{i=0}^{x-1}(f_i+\frac{i-j}{i})\),可以拆成斜率优化的形式。推出柿子之后直接 wqs 二分即可,然后似乎要注意精度。
CF739E link 猜测答案在两个维度上都是凸包形式,所以可以二分套二分。检查的过程就变成了对于一个物品,用红球有 \(p_A-c_A\) 的贡献,用蓝球有 \(p_B-c_B\) 的贡献,两个都用有 \(p_{A\&B}-c_A-c_B\) 的贡献,选择一个希望最大化总贡献,贪心即可,途中记录两种球各用几次。有些卡精度,应当在当前数量等于希望数量时及时推出。
aliens link 经典的题目。把右上的点翻到左下,消除那些对答案不产生影响的点,剩下的点会形成一个锯齿一样的形状,每个点映射到对角线上会有一个区间 \([l_i,r_i]\)。但由于多次选择的区间只会被计算一次,所以方程会稍微复杂一点(一开始以为要多次计算,调了半天才反应过来,毕竟那种思路下根本无法形成凸包)。内部还是用的斜率优化。
忘情 link 和上一道题本质上差不多。柿子题。
林克卡特树 link 转化问题。把树拆成 \(k\) 部分,然后要最大化连接起来后的答案,就贪心地选择每个部分中的直径。于是问题就变成了在树上选择 \(k+1\) 条不相交的链。因为所以这玩意是上凸的,所以采用 wqs 二分。用 \(f_{x,0/1/2}\) 代表这个点当前度数为多少时的最优值,考虑转移。用 \(g_x\) 代表 \(x\) 子树内的答案(也就是到父亲那条边不选),于是有
其中每个值都要记录两维,即答案和选择的链的数量。最后看 \(g_{root}\) 选择了几条链并更新左右端点即可。
CF802O link 运用到了 wqs 二分思想的题目。因为所以它是一个凸包,然后就可以用 wqs 二分了。考虑内部如何检查,这里用到了反悔 DP 的思想。考虑一个点作为结束时间时选择谁作为开始时间。如果选择一个没有被选择过的 \(a_y\),那么由于当前是一个新的决策,所以贡献是 \(b_x+a_y-v\)。如果是顶替掉之前的某个决策,那么贡献的变化值就是 \(b_x-b_y\),所以动态维护 \(a_y-v\) 和 \(-b_y\) 的最小值并记录第一种决策做了多少次即可。一只 \(\log\)。