https://www.acmicpc.net/problem/2512
문제
> 국가의 역할 중 하나는 여러 지방의 예산요청을 심사하여 국가의 예산을 분배하는 것이다.
> 국가예산의 총액은 미리 정해져 있어서 모든 예산요청을 배정해 주기는 어려울 수도 있다.
> 그래서 정해진 총액 이하에서 가능한 한 최대의 총 예산을 다음과 같은 방법으로 배정한다.
> 모든 요청이 배정될 수 있는 경우에는 요청한 금액을 그대로 배정한다.
> 모든 요청이 배정될 수 없는 경우에는 특정한 정수 상한액을 계산하여 그 이상인 예산요청에는 모두 상한액을 배정한다.
> 상한액 이하의 예산요청에 대해서는 요청한 금액을 그대로 배정한다.
> 예를 들어, 전체 국가예산이 485이고 4개 지방의 예산요청이 각각 120, 110, 140, 150이라고 하자.
> 이 경우, 상한액을 127로 잡으면, 위의 요청들에 대해서 각각 120, 110, 127, 127을 배정하고 그 합이 484로 가능한 최대가 된다.
> 여러 지방의 예산요청과 국가예산의 총액이 주어졌을 때, 위의 조건을 모두 만족하도록 예산을 배정하는 프로그램을 작성하시오.
접근
이분탐색으로 예산의 상한값을 mid값으로 잡아 mid값보다 요청값이 작으면 그냥 더하고, 크면 mid값만큼만 더하고를 반복하며 더한 값이 총 예산을 넘어가지 않는 mid값을 찾아낸다.
문제해결
> 지방수 N을 입력받고 필요예산을 money배열에 N크기로 입력받는다.
> exp는 필요예산 중 최대 값, sum은 총 필요예산 합이다.
> 필요예산을 입력받고 sum과 exp를 구한다.
> Max는 최대 예산이고 sum과 이를 비교해 예산삭감 없어도 총 예산으로 가능하면 exp를 출력하고 끝낸다.
> 아니면 예산을 삭감해야한다.
> 첫 left를 최대 예산을 지방 수로 나눈 값으로 가지고 right는 exp로 가진다.
> 앞서 sum이 max보다 작은 경우는 쳐냈기 때문에 가능하다.
> 이분탐색을 진행하며 sum에 min연산으로 상한보다 작으면 그대로 추가, 크면 mid값만큼만 추가해서 sum을 구한다.
> 이 sum이 총예산보다 크면 right값을 줄여 상한선을 줄여야하고
> 총예산보다 작으면 돈을 더 써도 되므로 left를 mid+1로 상한선을 늘려준다.
> 위 과정을 반복해 구한 최적의 right값을 출력한다.
코드
import java.io.*;
import java.util.*;
import java.lang.*;
public class Main {
//2512번 예산
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer st;
static StringBuilder sb = new StringBuilder();
public static void main(String[] args) throws IOException {
int N = Integer.parseInt(br.readLine());
int[] money = new int[N];
st = new StringTokenizer(br.readLine());
int exp = 0;
int sum = 0;
for(int i = 0; i < N; i++) {
money[i] = Integer.parseInt(st.nextToken());
sum += money[i];
exp = Math.max(money[i], exp);
}
int Max = Integer.parseInt(br.readLine());
if(sum <= Max) System.out.print(exp);
else {
int left = Max / N;
int right = exp;
int mid;
while(left <= right){
sum = 0;
mid = (left + right) / 2;
for(int i = 0; i < N; i++) {
sum += Math.min(money[i], mid);
}
if(sum <= Max) left = mid + 1;
else right = mid - 1;
}
System.out.print(right);
}
}
}

후기
첫 left와 right의 설정에 조금 복잡했지만 할만했다. 슬슬 어려워지기시작했다.