본문 바로가기

알고리즘(백준 등) 공부

백준 16801. 식신

n명의 먹는 사람들의 능력과 n개의 먹어야 할 음식들에 대한 값이 주어질 때, 점수는 능력 X 음식 의 값의 최댓값이 된다. 단련하여 1씩 능력을 줄여 0 까지 줄일 수 있고 k만큼 단련시킬 수 있을 때 점수의 최솟값을 구하는 문제이다.n <= 2* 10^5, k<= 10^18 이므로 모든 경우의 수를 세는 것이 아닌 최적의 경우의 수에서의 점수를 구해야 한다. 점수에 대한 이진탐색을 사용하여 최댓값을 구하였다.

 

이를 위해 능력과 음식들을 정렬한다.

players = new long[n];
st = new StringTokenizer(br.readLine());
for(int i=0; i<n; i++) players[i] = Long.parseLong(st.nextToken());
Arrays.sort(players);
            
foods = new long[n];
st = new StringTokenizer(br.readLine());
for(int i=0; i<n; i++) foods[i] = Long.parseLong(st.nextToken());
Arrays.sort(foods);

 

 

이진탐색은 점수에 대해 적용하였다. 정렬한 능력과 음식들을 서로 반대되는 위치의 값을 곱하는 것이 점수를 최대한 낮추는 최적의 방법이며 이진탐색의 점수를 최댓값으로 가지게 k를 사용할 때 가능한지 여부를 확인하면서 탐색하였다. 점수보다 큰 능력 X 음식값 을  기준으로 능력에 필요한 만큼만 빼줄 때 누적합이 k를 초과하게 되면 해당 점수 이하는 만들 수 없게 되며 시작점을 중앙+1로 이동한다. k 이하라면 해당 점수를 만들 수 있게 되어 종점을 중앙으로 이동한다. 종점이 시작점보다 작거나 같게 되면 구간의 종료가 되며 종점이 점수의 최솟값이 된다.

private static long binarySearch(long l, long r) {
    long start = l, end = r;
    while(end > start) {
        long mid = (start + end) / 2;
        long score = 0;
        for(int i=0; i<n; i++) {
            if(mid >= players[i] * foods[n -1 -i]) continue;
            score += players[i] - (mid / foods[n -1 -i]);
            if(score > k) {
                start = mid + 1;
                break;
            }
        }
        if(k >= score) {
            end = mid;
        }
    }
    return end;
}

 

 

결과 코드는 다음과 같다.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Solution {
    static long[] players;
    static long[] foods;
    static int n;
    static long k;
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int T = Integer.parseInt(br.readLine());
        StringBuilder sb = new StringBuilder();

        for (int tc = 1; tc <= T; tc++) {
            sb.append('#').append(tc).append(' ');
            StringTokenizer st = new StringTokenizer(br.readLine());
            n = Integer.parseInt(st.nextToken());
            k = Long.parseLong(st.nextToken());
            
            players = new long[n];
            st = new StringTokenizer(br.readLine());
            for(int i=0; i<n; i++) players[i] = Long.parseLong(st.nextToken());
            Arrays.sort(players);
            
            foods = new long[n];
            st = new StringTokenizer(br.readLine());
            for(int i=0; i<n; i++) foods[i] = Long.parseLong(st.nextToken());
            Arrays.sort(foods);
            
            long answer = binarySearch(0, players[n-1] * foods[n-1]);
            sb.append(answer).append('\n');
        }
        
        br.close();
        System.out.print(sb);
    }
    
    private static long binarySearch(long l, long r) {
        long start = l, end = r;
        while(end > start) {
            long mid = (start + end) / 2;
            long score = 0;
            for(int i=0; i<n; i++) {
                if(mid >= players[i] * foods[n -1 -i]) continue;
                score += players[i] - (mid / foods[n -1 -i]);
                if(score > k) {
                    start = mid + 1;
                    break;
                }
            }
            if(k >= score) {
                end = mid;
            }
        }
        return end;
    }
}

'알고리즘(백준 등) 공부' 카테고리의 다른 글

SWEA 16003. 화면 캡쳐  (0) 2026.05.05
SWEA 16800. 구구단 걷기  (0) 2026.05.04
SWEA 16910. 원 안의 점  (0) 2026.05.03
SWEA 17299. 최소 덧셈  (0) 2026.05.03
SWEA 17319. 문자열문자열  (0) 2026.05.02