题意
个区间,从每个区间取一个数,要求最后中位数尽可能大
题意
第一反应就是二分
但是我,二分单调性的理解,很差
我就否决了,去想枚举,然后我就没了。
实际上就是二分中位数,对于一个中位数,肯定有一部分在你左边,一部分在你右边。
如果左边部分超过一半了,说明这个中位数过大了。
如果右边部分超过一半了,说明这个中位数过小了。
如果正常情况下,剩下的只剩的区间了,这个时候就先取最小的左端点使得左边的取满一半,然后使右边取满一半+1,右边的贡献就是中位数大小
如果这个和比小,说明符合情况,再取更大的中位数。
反之,不符合情况,取更小的中位数。
在保证左右两边都不超过的情况,你如何证明单调性呢?
首先贡献肯定是绝大部分取左端点,少部分取中位数。
大概是这样:
、 保证在左边和右边的部分,首先他们不会超限,并且他们一定取左端点。
、部分就是包含中位数的部分,左边一部分取左端点,右边取中位数。
所以对原区间排序,前一半一定取左端点。
我们考虑增大中位数,显然如果先决条件成立,随着中位数增大,能够选择的区间会越多,也就是要变成中位数的越多。
表示后缀左坐标之和
比较可以发现,左部分是增大的,右部分是缩小的。
但是右部分减去的左端点,都在左部分变成了,而肯定是大于等于左端点的。
并且还变成了,所以。满足单调性。
总结
这是我遇到的或者说第一次带合法的二分。
准确来说对于不合法情况,显然满足二分,左边多了说明大了,右边多了说明小了。
在合法情况下,也满足二分,因为左边部分一定取左端点,右边部分随着中位数变大,取中位数变多了,虽然说取左坐标的减少了,但那时因为他们都去取中位数了,所以贡献一定变大。
#include<bits/stdc++.h>
#define FOR(i,l,r) for(int i=l;i<=r;i++)
#define sf(x) scanf("%d",&x)
typedef long long ll;
using namespace std;
const ll mod = 1e9+7;
const int maxn = 2e5+100;
struct node{
int l,r;
friend bool operator < (node a,node b){
if(a.l==b.l)return a.r<b.r;
return a.l<b.l;
}
}A[maxn];
int n;ll s;
bool check(int x){
int lt=0,rt=0;
ll ret=0;
//cout<<x<<endl;
for(int i=1;i<=n;i++){
if(A[i].r<x)lt++,ret+=A[i].l;
else if(A[i].l>x)rt++,ret+=A[i].l;
}
if(rt>=n/2+1)return true;
if(lt>=n/2+1)return false;
for(int i=1;i<=n;i++){
if(A[i].r<x||A[i].l>x)continue;
if(lt<n/2)ret+=A[i].l,lt++;
else ret+=x,rt++;
}
return ret<=s;
}
int main(){
int T;cin>>T;
while(T--){
scanf("%d%lld",&n,&s);
FOR(i,1,n)scanf("%d%d",&A[i].l,&A[i].r);
sort(A+1,A+1+n);
int l=1,r=1e9+1,ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)){
ans=max(ans,mid);
l=mid+1;
}
else r=mid-1;
}
printf("%d\n",ans);
}
}
来源:CSDN
作者:mxYlulu
链接:https://blog.csdn.net/mxYlulu/article/details/104246811