Codeforce 1251 D. Salary Changing(二分答案 + 贪心)

mac2024-02-22  60


题意:有 n 个人,每个人的工资的有个区间 [ l , r ] [l,r] [l,r],你手上总共有 s s s 金额。你给这 n 个人发工资,工资金额必须满足他们的区间要求。问要使得中位数最大,最少要发多少钱出去。

直接二分答案,对当前答案求出最少需要的金额 f f f,对于 m i d mid mid, 至少要有 ⌊ n + 1 2 ⌋ \lfloor\frac{n + 1}{2}\rfloor 2n+1 个人的工资 ≥ m i d \geq mid mid。将 n 个人划分成三类: 1. r < m i d r <mid r<mid, 这类人发 l l l 的工资 2. l ≤ m i d ≤ r l \leq mid \leq r lmidr,这类人按 l l l 排序,若工资 ≥ m i d \geq mid mid 的人不够 ⌊ n + 1 2 ⌋ \lfloor\frac{n + 1}{2}\rfloor 2n+1,则发 m i d mid mid,否则发 l l l 3. m i d < l mid < l mid<l,这类人发 l l l ,由于 l > m i d l > mid l>mid,因先发这一类人

综上,将每个人的工资按 l l l 从大到小排序,二分答案,贪心构造即可。


#include<bits/stdc++.h> using namespace std; const int maxn = 2e5 + 10; typedef long long ll; int t; ll L[maxn],R[maxn],n,s; struct node{ ll l,r; node(ll li = 0,ll ri = 0) { l = li; r = ri; } bool operator < (const node & rhs) const { if(l == rhs.l) return r > rhs.r; return l > rhs.l; } }a[maxn]; int main() { scanf("%d",&t); while(t--) { scanf("%lld%lld",&n,&s); for(int i = 1; i <= n; i++) { scanf("%lld%lld",&a[i].l,&a[i].r); } sort(a + 1,a + n + 1); ll l = 0,r = s + 1; while(l < r) { ll mid = l + r >> 1; ll tmp = 0,cnt = 0; for(int i = 1; i <= n; i++) { if(mid < a[i].l){ tmp += a[i].l; cnt++; } else if(a[i].l <= mid && mid <= a[i].r) { if(cnt < (n + 1) / 2) tmp += mid,cnt++; else tmp += a[i].l; } else if(a[i].r < mid) tmp += a[i].l; } if(cnt >= (n + 1) / 2 && tmp <= s) l = mid + 1; else r = mid; } printf("%lld\n",l - 1); } return 0; }
最新回复(0)