题意:给出n个人(n是奇数),s钱;s为总的可以付工钱的钱;
每一个工人有一个付工钱的区间,只要在这个区间范围内,随便一个数都可以当作给这个工人付了钱;
老板要付给每个工人钱,并且付钱的中位数要尽可能大;
问:最大的中位数是多少;
思路:贪心+思维+二分;
我们以中位数为主体进行二分。那么就需要n/2+1个大于等于中位数的数;
这个时候我们先给钱排序,按第一个数从大到小排;
然后check部分,从1到n遍历,如果满足x在区间范围内,就取x这个数;
那么,为什么就要取这个数呢,因为我们迟早要凑到n/2+1个数,所以从大到小的排序,可以让我们在使用的钱
最少的情况下,取出这n/2+1个这样的数; 比如有这样两个区间“6 10” ”7 11“ 按从大到小排序,我们假如中位数为8;
我们假如“6 10" 取中位数8 ”7 11“ 取左端点7 那么结果为15
如果”7 11“ 取中位数, 另一个取左端点,则结果为14;
所以代码如下
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=2e5+10; 5 struct node 6 { 7 int l,r; 8 }a[maxn]; 9 ll n;ll s; 10 bool cmp(node x,node y) 11 { 12 return x.l>y.l; 13 } 14 int check(ll x) 15 { 16 ll sum=0; 17 ll num=n/2+1; 18 for(int i=1;i<=n;i++){ 19 //当num==0之后,所需要的大于等于n/2+1已经满足,所以都取 20 //左端点即可; 21 if(x>=a[i].l&&x<=a[i].r&&num>0){ 22 sum+=x; 23 num--; 24 } 25 else{ 26 sum+=a[i].l; 27 if(a[i].l>=x) num--; 28 } 29 } 30 if(num>0) return 0; 31 else{ 32 if(sum>s) return 0; 33 else return 1; 34 } 35 } 36 int main() 37 { 38 int T; 39 scanf("%d",&T); 40 while(T--){ 41 scanf("%lld%lld",&n,&s); 42 for(int i=1;i<=n;i++){ 43 scanf("%d%d",&a[i].l,&a[i].r); 44 } 45 sort(a+1,a+1+n,cmp); 46 ll l=a[n/2+1].l;ll r=s; 47 ll ans=l; 48 while(l<=r){ 49 ll mid=l+r>>1; 50 if(check(mid)){ 51 ans=mid; 52 l=mid+1; 53 } 54 else r=mid-1; 55 } 56 printf("%lld\n",ans); 57 } 58 return 0; 59 }
原文地址:https://www.cnblogs.com/pangbi/p/12203295.html
时间: 2024-11-14 00:08:40