본문 바로가기

Algorithms/PS

[PS] 백준 #16564. 히오스 프로게이머

문제 정보

 

문제

성권이는 Heroes of the Storm 프로게이머 지망생이다.

이 게임에는 총 N개의 캐릭터가 있다. 그리고 현재 각 캐릭터의 레벨은 Xi이다. 성권이는 앞으로 게임이 끝날 때까지, 레벨을 최대 총합 K만큼 올릴 수 있다.

팀 목표레벨 T =min(Xi) (1 ≤ i ≤ N)라고 정의하면, 게임이 끝날 때까지 성권이가 달성할 수 있는 최대 팀 목표레벨 T는 무엇인가?

예를 들어, N = 3, X1= 10, X2= 20, X3= 15이고 K = 10일 때, X1을 7만큼 올리고 X3을 2만큼 올리면 최소 레벨 Xi는 17이 된다. 따라서 팀 목표레벨 T는 17이다. 이 경우처럼 레벨을 총합 K보다 적게 올릴 수도 있다.

 

나의 풀이

풀이 1: 내 풀이

레벨들을 정렬한 후, T값은 가장 낮은 레벨에서 시작한다. 가장 낮은 레벨이 두번째 레벨만큼 올라오면 T는 두번째 레벨로 갱신해주고 k는 (charCount * 두 레벨의 차이)만큼 감소, charCount는 1 증가시킨다. 만약 k값이 두 레벨의 차이만큼 올리기에 충분하지 않을 경우 몫 계산해서 반복문을 종료한다. 

#include <bits/stdc++.h>
using namespace std;

int main() {
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	vector<int> levels;
	int n, k;
	cin >> n >> k;
	levels.push_back(0); // 0번째 값은 쓰레기값
	for (int i = 0; i < n; i++) {
		int a; cin >> a; levels.push_back(a);
	}

	// levels 오름차순 정렬
	sort(levels.begin(), levels.end());

	// T값은 가장 낮은 레벨에서 시작한다. 
    // 가장 낮은 레벨이 두번째 레벨만큼 올라오면 T는 두번째 레벨로 갱신
    // k는 (charCount * 두 레벨의 차이)만큼 감소하고, charCount 1 증가
    // 만약 k값이 두 레벨의 차이만큼 올리기에 충분하지 않을 경우 몫 계산해서 반복문 종료
	int T = levels[1];
	int charCount = 1;
	while (k > 0) {
		if (charCount < levels.size()) {
			if ((levels[charCount + 1] - levels[charCount]) * charCount <= k) {
				T = levels[charCount + 1];			
				k -= (levels[charCount + 1] - levels[charCount]) * charCount;
				charCount++;
			}
			else {
				T += k / charCount; break;
			}
		}
		else break;
	}

	cout << T;
}

 

풀이 2: 이분탐색

대회가 끝난 후 해설을 보니 원래는 이분 탐색을 이용한 풀이가 정석 방법인 것 같았다. 내가 푼 풀이가 이분 탐색을 사용한 풀이인지는 잘 이해가 안가서.. 다시 아래와 같이 풀어보았다. 나는 예전부터 이분 탐색 관련 문제들은 잘 눈치채지 못하는 경우가 많았어서 이 테마는 조금 더 연습이 필요할 것 같다. 

l과 r을 T값의 범위라고 생각하자. 이분탐색의 각 과정마다 l과 r의 중간인 mid 를 계산하고, mid보다 작은 레벨들과의 차이를 dt에 추가하자. dt가 k보다 크면 r을 mid-1로 옮겨서 범위를 좌측 반으로 줄인다. dt가 k와 같거나 작으면 answer에 mid를 대입하고, l을 mid+1로 옮겨서 범위를 우측 반으로 줄인다. 이 과정을 반복하다가 l > r이 되서 알고리즘이 종료된다. 그 때의 mid값이 최종 정답이다.

#include <bits/stdc++.h>
using namespace std;

int main() {
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	vector<int> levels;
	int n, k;
	cin >> n >> k;
	levels.push_back(0); // 0번째 값은 쓰레기값
	for (int i = 0; i < n; i++) {
		int a; cin >> a; levels.push_back(a);
	}

	sort(levels.begin(), levels.end());

	long dt, l = 0, r = 1000000000, answer;
	while (l <= r) {
		long mid = (l + r) / 2;
		dt = 0;
		// mid 보다 작을때만 dt값 갱신
		for (int i = 1; i <= n; i++) {
			if (levels[i] < mid) dt  += mid - levels[i];
		}
		if (dt > k) {
			r = mid - 1;
		}
		else {
			answer = mid;
			l = mid + 1;
		}
	}

	cout << answer;
}

'Algorithms > PS' 카테고리의 다른 글

[PS] 백준 #14502. 연구소  (0) 2022.01.17
[PS] 백준 #21937. 작업  (0) 2022.01.17
[PS] 백준 #19949. 영재의 시험  (0) 2022.01.17
[PS] 백준 #17390. 이건 꼭 풀어야 해!  (0) 2022.01.17
[PS] 백준 #4673. 셀프 넘버  (0) 2022.01.16