wqs二分小结

感觉一般可能要严谨证明的话还是有点麻烦,不如直接打表,或者先老实WA一发 来的快

  • 一般题目会有选恰好k个/次这样的限制
  • 大致就是通过二分斜率,然后通过dp,或者贪心计算出最大/最小值,然后通过判断这个最大/最小值对应的选的个数来调整
  • 需要注意的是,我们计算的相当于是截距,还要+/-kl才是答案

例题

https://www.luogu.com.cn/problem/CF802N为例
给定两个长度为 \(n\) 的序列 \(a_1, a_2, \ldots, a_n\)\(b_1, b_2, \ldots b_n\)。要求选出 \(i_1, i_2, \ldots, i_k\)\(j_1, j_2, \ldots, j_k\),满足

  • \(1\leq i_1< i_2<\ldots< i_k\)\(1\leq j_1< j_2<\ldots< j_k\)

  • \(i_p\leq j_p\)\(1\leq p \leq k\))。

最小化 \(\sum_{p=1}^k a_{i_p}+b_{j_p}\) 的值。

  • 首先我们来感性理解一下
  • 假如我们不考虑k这个限制,因为都是正的,肯定是一个都不选
  • 但是如果我们给每个\(b_i\)都减上一个数x,就有可能出现选的情况,并且随着数x的增大,选的数肯定是越来越多
  • 因此我们可以二分这个x,计算出选了多少个数,从而对x进行调整

更具体的分析

#include<bits/stdc++.h>
#define fo(i,a,b) for (ll (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (ll (i)=(b);(i)>=(a);(i)--)
#define lc (o<<1)
#define rc ((o<<1)|1)
#define mk(x,y) make_pair((x),(y))
#define eb emplace_back
#define A puts("Yes")
#define B puts("No")
#define fi first
#define se second
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
typedef long long i64;
const ll inf=1ll<<60;
const ll mo1=1e9+9;
const ll mo2=1e9+7;
const ll P=131;
const ll Q=13331;
const int N=1e6+5;
struct node{
	ll x,op;
};
bool operator < (const node &a,const node &b){
	if (a.x!=b.x) return a.x>b.x;
	return a.op>b.op;
}
priority_queue<node> q;
ll n,k,a[N],b[N],ans;
ll check(ll x){
	while (!q.empty()) q.pop();
	
	ll cnt=0;	
	ans=0;
	fo(i,1,n) {
		q.push((node){a[i],0});
		if (b[i]-x+q.top().x<=0) {
			ans+=b[i]-x+q.top().x;
			if (!q.top().op) cnt++;
			q.pop();
			q.push((node){-(b[i]-x), 1});
		}
	}
	
	return cnt;
}
int main(){
//	freopen("data.in","r",stdin);
	
	scanf("%lld %lld",&n,&k);
	fo(i,1,n) scanf("%lld",&a[i]);
	fo(i,1,n) scanf("%lld",&b[i]);
	
	ll l=0,r=1e12,mid;
	while (l<r) {
		mid=(l+r)>>1;
		if (check(mid)>=k) r=mid;
		else l=mid+1;
	}

	check(l);
	printf("%lld",ans+k*l);
	

	return 0;
}
 
 
  • 在反悔贪心的时候,注意到是可以取等,并且权值相同时,优先让a在前面,就是为了尽可能的多选数。
  • 也就是说我们得到的是跟这条直线相切的最右端点
  • 因此只有当\(k \le cnt\)时才可能合法
  • 当mid增大时,cnt会增大,因此我们要二分得到最小的mid使得\(k \le cnt\)
posted @ 2024-08-27 08:40  gan_coder  阅读(22)  评论(0)    收藏  举报