观察这个小柿子有什么特点:
\[y_i=\sum\limits_{j=l_i}^{r_i} [w_j\ge W]\times\sum\limits_{j=l_i}^{r_i}[w_j\ge W]v_j \]我们要求的是 \(\vert s-y \vert\) 的最小值,\(s\) 恒定,而 \(y\) 可以发现是与 \(W\) 负相关的。\(W\) 增大时,\(y_i\) 减小,故 \(y\) 减小;\(W\) 减小时,\(y_i\) 增大,故 \(y\) 增大。这样,我们可以二分 \(W\)。不同于一般情况下 check 得到的 \(mid\) 是否成立,我们在 \(y>s\) 时增大 \(W\) 以减小 \(y\),在 \(y<s\) 时减小 \(W\) 以增大 \(y\)。如下所示:
//in check()
res=abs(s-Y);
if(Y>s) return true;
else return false;
//in main()
while(l<r) {
int mid=(l+r)>>1;
if(check(mid)) l=mid+1;
else r=mid-1;
ans=min(ans,res);//更新|s-y|最小值
}
如果只是这样二分显然会 TLE,我们发现上面的式子可以前缀和处理,最终时间复杂度为 \(\mathcal{O(n+m)\log W}\)。