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\)

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号