题意:一共有S元,给n个人分,每个人允许分到的钱数有一个范围( l ~ r ),可以不用完s,问最大的中位数是多少
思路:当时做到这里的时候宿舍也熄灯了,脑子还巨困。。。
比赛的时候想的是把全部人按照( l , r )排序,然后二分中间那个人的可分配范围,看最多能给这个人分配多少钱。
但是这么写有个问题,,,可能不用中间那个人作为中位数,如:
2 4 2 7 4 4 5 6 6 8这种情况下,如果按照我的思路是4,但是显然可以有,2,7,4,6,8。。。类似这种取法,原因在于 l 小的人可能 r 大,那么他可以取到更大的范围,这么排列就没啥用了!
昨天晚上一直在绞尽脑汁想到底按啥排序,但是其实有问题的是二分。。
二分的时候直接二分1--1e9,每次找出可以比这个值大的数有多少,大于n/2则可能成为中位数,然后贪心分配钱数就好了。
总结:。。还是想的太少
vector<pair<ll, ll> > v, v1; void solve() { ll n, s,l, r, best; ll low, high, mid, val, temp, flag; rd(n),rd(s);v.clear(); val = n / 2 + 1; for (int i = 0; i < n; i++) { rd(l),rd(r); v.push_back({l, r}); } sort(v.begin(), v.end()); low = 0;// high = 1e9;// while (low <= high) { flag = 1; mid = (low + high) / 2; v1.clear(); temp = 0; for (int i = 0; i < v.size(); i++) { if (v[i].second >= mid) v1.push_back(v[i]); else temp += v[i].first; } if (v1.size() < val) flag = 0; else { ll idx = v1.size() - val; for (int i = 0; i < v1.size(); i++) { if (i < idx) temp += v1[i].first; else temp += max(mid, v1[i].first); } if (temp > s) flag = 0; } if (flag) best = mid,low = mid + 1; else high = mid - 1; } printf("%lld\n",best); } int main() { int t;rd(t); while (t--) solve(); return 0; }