https://codeforces.com/contest/1251/problem/D
보자마자 이분탐색이나 dp겠구나 싶어서 이분탐색으로 접근했다. 하지만 시간이 부족해서 10분정도 오버해서 풀었다.
설명)
사람의 수 n과 가지고 있는 돈 s가 주어지고 n명의 사람에 대해 받을 수 있는 돈의 범위 [l,r]이 주어진다. 이 때 사람들에게 나누어주는 돈의 중간값의 최대를 구하는 문제이다.
l을 기준으로 사람들을 오름차순 정렬한다면 l, l, .... l, m, max(m,l), max(m, l) ... max(m,l) 인 경우가 최적이다.
m값을 기준으로 오른쪽에 위치할 수 있는 사람은 r의 값이 m이상이어야 한다. 중간값 우측의 사람 수가 n/2미만이라면 그 값을 중간값으로 사용할 수 없다.
이 부분이 생각하기 좀 어려웠던 부분인데, 예를들어 s=26, arr에 (1,4), (10,11), (10,14)가 저장되어 있을 때 최대 중간값은 10이다. 이분탐색 시 이 값을 도출 하기 위해서 10이하의 값은 유효한 것으로 간주해야 한다는 의미다. 하지만 그 어떤 범위에도 속하지 않는 7(예를들어)은 사실 불가능한 중간값이다. 이런 값을 참이라고 넘기면 이분탐색의 특징에 따라서 결과적으론 유효한 최대값을 반환해 준다..
#include <iostream>
#include <algorithm>
#include <utility>
#include <vector>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
vector<P> arr;
ll n, s;
bool isPossible(ll m) {
int cnt = 0;
ll sum = 0;
for (int i = n - 1; i >= 0; i--) {
ll l = arr[i].first, r = arr[i].second;
if (m<=r && cnt <= n/2) {
cnt++;
sum += max(l, m);
}
else
sum += l;
}
if (cnt <= n / 2 || sum > s) return false;
return true;
}
int main() {
int t; cin >> t;
while (t--) {
cin >> n >> s;
arr.resize(n);
ll lo = 1e9, hi = 0;
for (int i = 0; i < n; i++) {
cin >> arr[i].first >> arr[i].second;
lo = min(lo, arr[i].first);
hi = max(hi, arr[i].second);
}
sort(arr.begin(), arr.end());
while (lo < hi) {
ll mid = (lo + hi+1) / 2;
if (isPossible(mid)) lo = mid;
else hi = mid-1;
}
cout << lo << '\n';
}
}
'알고리즘 > 코드포스' 카테고리의 다른 글
codeforces #580 div2 D - Shortest Cycle (무방향그래프 사이클, 비둘기집) (0) | 2019.11.13 |
---|---|
codeforces #580 div2 C - Almost Eqaul (발상) (0) | 2019.11.13 |
Educational round #73 D - Make the fence great again (dp) (0) | 2019.11.07 |
codeforces #581 div2 C - Anna, Svyatoslav and Maps ( 플로이드 ) (0) | 2019.11.04 |
codeforces #597 div2 D - Shichikuji and Power Grid ( MST ) (0) | 2019.11.04 |