考虑一个暴力的费用流:
由于费用流可以一点一点地增加流量,只要増广\(k\)次即可求出答案。
注意到费用流每增加一点流量,所需的费用肯定是单调不减的。
也就是说这是一个凸函数,那么就可以使用\(WQS\)二分来优化。
我们二分一个额外价值\(mid\)(\(mid<0\)),把所有\(a_i,b_j\)变成\(a_i+mid,b_j+mid\)。
此时就可以模拟费用流了,每个\(a_i\)只能无脑入堆,而每个\(b_j\)可以选择与一个\(a_i\)配对或是替换掉先前某个\(b_j‘\)(注意后者不会使配对数加\(1\),需要在堆中记录元素类型)。
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Rg register
#define RI Rg int
#define Cn const
#define CI Cn int&
#define I inline
#define W while
#define N 500000
using namespace std;
int n,k,a[N+5],b[N+5];long long ans;
namespace FastIO
{
#define FS 100000
#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
char oc,FI[FS],*FA=FI,*FB=FI;
Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
}using namespace FastIO;
typedef pair<int,int> Pr;priority_queue<Pr,vector<Pr>,greater<Pr> > Q;I bool Check(CI x)//模拟费用流
{
RI i,t=ans=0;W(!Q.empty()) Q.pop();for(i=1;i<=n;++i)
{
if(Q.push(make_pair(a[i]+x,1)),Q.top().first+(b[i]+x)>=0) continue;//如果价值非负,无法产生贡献
ans+=Q.top().first+(b[i]+x),t+=Q.top().second,Q.pop(),Q.push(make_pair(-(b[i]+x),0));//配对/替换;令当前b入堆方便以后替换
}return t<=k;
}
int main()
{
RI i;for(read(n,k),i=1;i<=n;++i) read(a[i]);for(i=1;i<=n;++i) read(b[i]);
RI l=-1e9,r=0,mid;W(l^r) Check(mid=l+r-1>>1)?r=mid:l=mid+1;return Check(r),printf("%lld\n",ans-2LL*k*r),0;//WQS二分
}
【CF802O】April Fools' Problem (hard)(WQS二分+模拟费用流)
原文:https://www.cnblogs.com/chenxiaoran666/p/CF802O.html