wqs 二分简记
wqs 二分一般用于解决这样的问题: 个物品,恰好选 个获得的最大或最小价值为 ,求 。 需要具有凸性质。
二分一个斜率 ,check 时,用斜率为 的直线去切凸包。具体地,将每个物品的价值减去 ,取消个数限制,求出最大或最小的价值 和此时选择的物品个数 ,则可以发现 ,故切点为 。如果它不是切点,其对应的截距必然更劣。可以画图理解。如果有多个切点,可以想办法保证取到最左或者最右的切点。
基本上是 wqs 二分的模板题。首先我们可以将题目转化为:一张左右各 个点的二分图,左部第 个点向右部 的点连边,一个匹配的权值为两点的点权和,求恰好 对匹配的最小权值和。这显然是一个费用流模型,我们知道费用流问题肯定是凸的(现在我还不会证明),所以这个函数应当是下凸的。
于是跑 wqs 二分,check 是一个很容易的反悔贪心,注意实现细节保证取的匹配数最少或最多。
#include<bits/stdc++.h>
using namespace std;
constexpr int N=5e5+5;
typedef long long ll;
typedef pair<ll,int>pli;
int n;ll a[N],b[N];
pli check(ll k){
ll sum=0;int cnt=0;
priority_queue<pli,vector<pli>,greater<pli>>q;
for(int i=n;i>=1;i--){
q.emplace(b[i]-k,i);
if(q.top().first+a[i]<0){
auto[val,pos]=q.top();q.pop();
sum+=a[i]+val;cnt+=!!pos;
q.emplace(-a[i],0);
}
}
return pair(sum,cnt);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int K;cin>>n>>K;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
ll l=0,r=2e9,ans=1;while(l<=r){
ll mid=(l+r)>>1;
auto[b,cnt]=check(mid);
if(cnt<=K)ans=b+mid*K,l=mid+1;
else r=mid-1;
}
cout<<ans<<'\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现