https://www.acmicpc.net/problem/28357
문제
소수전공 수업을 마무리한 찬우는 축하의 의미로 학생들에게 사탕을 나누어 주려 한다. 구체적으로, 기준이 되는 음이 아닌 정수 X를 정한 뒤 최종 점수가 X점을 넘는 학생들에게 점수가 높은 만큼 많은 사탕을 줄 것이다. 즉, X+1점을 받은 학생은 1개, X+2점을 받은 학생은 2개, T(T>X)점을 받은 학생은 T−X개의 사탕을 받게 된다.
찬우는 학생들에게 최대한 많은 사탕을 나누어주고 싶기 때문에 기준 점수 X를 가능한 한 낮게 정하려 한다. 하지만, 지금 가지고 있는 돈으로는 사탕을 K개까지만 살 수 있기 때문에 사탕의 총 개수가 K개를 넘으면 안 된다.
찬우의 수업은 총 N명이 수강했고, i번째 학생은 Ai점을 받았다. 수강생의 수와 각 학생의 점수, 사탕의 최대 개수 K가 주어질 때 찬우를 위해 가능한 X의 최솟값을 구하는 프로그램을 작성해 주자.
입력
첫째 줄에 정수 N, K가 공백으로 구분되어 주어진다. (1 ≤ N ≤ 5×105 0 ≤ K ≤ 1012)
둘째 줄에 N개의 정수 A1, A2, ⋯, AN이 공백으로 구분되어 주어진다. (0 ≤ Ai ≤ 1012)
출력
첫째 줄에 가능한 기준 X의 최솟값을 출력한다.
문제 풀이
이분탐색 문제.
주어진 값이 크므로 O(logn)에 탐색 가능한 이분 탐색 문제임을 유추할 수 있다. 이분 탐색의 mid를 기준점인 X로 잡는 매개변수 탐색을 진행하면 된다. 입력한 값들을 정렬한 후 left와 right로 mid를 정한 후, mid보다 큰 점수라면 해당 값에서 mid를 뺀다. 이 값들의 합이 M이 되는 mid의 최솟값을 구해주면 된다. 만약 준 사탕의 개수가 M보다 크다면 mid 값을 너무 작게 잡아 사탕을 너무 많이 나누어 준 것이다. 준 사탕의 개수가 M보다 작다면 기준점인 mid 값을 너무 크게 잡아 사탕을 너무 작게 준 것이다. 물론 나누어주는데에는 문제 없으므로 mid값을 저장하며 최솟값을 갱신시켜주면 된다.
아래는 코드.
#include <iostream>
#include <algorithm>
#include <climits>
using namespace std;
long long* arr;
long long N, M;
long long answer;
void binarySearch(long long start, long long end)
{
long long left = start;
long long right = end;
while (left <= right)
{
long long standard = (left + right) / 2;
long long candySum = 0;
for (int i = 0; i < N; i++)
{
if (arr[i] < standard)
{
continue;
}
else
{
candySum += arr[i] - standard;
}
}
if (candySum <= M)
{
answer = min(answer, standard);
right = standard - 1;
}
else
{
left = standard + 1;
}
}
}
int main()
{
cin.tie(NULL);
ios::sync_with_stdio(false);
answer = LLONG_MAX;
cin >> N >> M;
arr = new long long[N];
for (int i = 0; i < N; i++)
{
cin >> arr[i];
}
sort(arr, arr + N);
binarySearch(0, 1000000000001);
cout << answer << "\n";
return 0;
}
'알고리즘 > 백준' 카테고리의 다른 글
[백준 16562] 친구비 (C++) (0) | 2025.01.11 |
---|---|
[백준 20115] 에너지 드링크 (C++) (0) | 2025.01.10 |
[백준 1339] 단어 수학 (C++) (0) | 2025.01.08 |
[백준 28075] 스파이 (C++) (0) | 2025.01.07 |
[백준 13265] 색칠하기 (C++) (0) | 2025.01.06 |