D. Salary Changing(二分,贪心取区间)

. . . ! ! 一开始我就在想不二分怎么找答案...但是单调性呢!!

其实是有单调性的。

l , l L 先按照区间l排序,显然当都取l时中位数最小是中间的L

r , r R 按照区间r排序,显然当都取r时中位数最大是中间的R

所以在区间[L,R]中满足单调性,可以二分

? ? \color{Red}如何二分??

K = n / 2 + 1 m i d 首先要找K=n/2+1个区间大于等于mid

三种情况

. r < m i d , m i d , l Ⅰ.区间的r<mid,那么不管怎么发薪水都会小于mid,不如发l最少

. l > m i d , m i d , K l Ⅱ.区间l>mid,不管怎么发都会大于mid,那么K--,同时加上l

. m i d Ⅲ.剩下的区间都是包含了mid的

扫描二维码关注公众号,回复: 11340043 查看本文章

l , K m i d 所以我们选掉l最小的一些区间,然后剩下K个区间选mid即可

, s o r t 代码中这一步是优先队列实现的,也可以排序sort

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
ll t,n,m;
struct p{
	ll l,r;
	bool operator < (const p&tmp )	const{
		return l<tmp.l;
	}
}a[maxn];
bool col(p a,p b){
	return a.l<b.l;
}
bool cor(p a,p b){
	return a.r>b.r;
}
bool isok(ll mid)
{
	priority_queue<p>q;
	ll temp=0,k=n/2+1;//需要有k个数大于等于mid 
	for(int i=n;i>=1;i--)
	{
		if(a[i].r>=mid&&a[i].l<=mid)	q.push( a[i] );
		else if(a[i].l>mid)	temp+=a[i].l,k--;//一定选
		else	temp+=a[i].l; 
	}
	if(k < 0)	return false;
	while(!q.empty())
	{
		p u=q.top(); q.pop();
		if(k)
			k--,temp+=mid;
		else	temp+=u.l;
	}
	if(temp>m||k!=0)	return false;
	else	return true;
}
int main()
{
	cin >> t;
	while(t--)
	{
		ll l=1e9,r=0,ans=-1;
		cin >> n >> m;
		for(int i=1;i<=n;i++)
			cin >> a[i].l >> a[i].r;
		sort(a+1,a+1+n,col);l=a[n/2+1].l;
		sort(a+1,a+1+n,cor);r=a[n/2+1].r;
		while(r>=l)
		{
			ll mid = l+r>>1;
			if( isok(mid) )	l=mid+1,ans=mid;
			else r=mid-1;
		}
		cout << ans << endl;
	}
}

猜你喜欢

转载自blog.csdn.net/jziwjxjd/article/details/106870149