二分题 D - Salary Changing codeforce

题意:给出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 }
posted @ 2020-01-16 21:16  古比  阅读(147)  评论(0编辑  收藏  举报