알고리즘

[Algorithm/Java] 백준 1561 놀이공원

지수쓰 2022. 1. 30. 21:48
반응형
/*
백준 1561번 놀이공원
문제링크 https://www.acmicpc.net/problem/1561
유형 : 이분 탐색 
*/
package com.company;

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

public class Play {
    static int N, M;
    static int[] time;
  public static void main(String[] args) throws IOException {

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    StringTokenizer st = new StringTokenizer(br.readLine());

    N = Integer.parseInt(st.nextToken());
    M = Integer.parseInt(st.nextToken());

    time = new int[M + 1];
    st = new StringTokenizer(br.readLine());
    for (int i = 1; i <= M; i++) {
        time[i] = Integer.parseInt(st.nextToken());
    }
    if(N<=M) System.out.println(N);
    else {
        long searchTime = binarySearch() - 1;
        long child = M;
        for (int i = 1; i <= M; i++) {
            child += searchTime / time[i];
        }

        for(int i=1; i<=M; i++){
            if( (searchTime+1)%time[i]==0) child++;
            if( child==N){
                System.out.println(i);
                return;
            }
        }

    }

}
static long binarySearch() {
    long left = 0;
    long right = (N/M) * 30L;
    long result = -1;

    while (left <= right) {
        long mid = (left + right) / 2;
        long child = M;
        for (int i = 1; i <= M; i++) {
            child += mid / time[i];
        }

        if (child < N) {
            left = mid + 1;
        } else {
            right = mid-1;
        }
    }
    return left;
}

처음엔 현재 타는 시간에 대해서 우선순위큐로 poll하면서 다음 타음시간 다시 넣어주고.. 뽑는 방식으로 풀어봤는데 메모리초과가났다. 

결국엔 풀이방법을 못찾아서 풀이들을 찾아봤다.  
표를 그려서 문제를 풀다보면 T분에 놀이기구를 탄 인원이 M + T/time[1]+T/time[2]+T/time[3] + .. + T/Time[M] 인 것을 알 수 있다.

N명의 인원을 모두 채우기 위해서 몇분이 걸리는지 이분탐색 으로 알아낸 뒤, 그중에 몇번째 놀이기구가 마지막으로 탄건지 알기 위해 T-1분까지의 놀이기구를 탄 인원을 미리 계산하고, 1~M번 놀이기구를 확인하며 사람을 태울수 있는지 카운트를 세어 N이 되는 순간의 놀이기구 번호를 알아내면 된다.

24 5  
1 2 2 4 4
예시 표

8분 4번에서 24명을 태우므로 이분탐색을 통해 8분인걸 알아내고,  7분까지의 결과인 20을 child변수에 저장한 뒤에 
M 에 대해서 순차적으로 i=1 ~ 5 까지 8%time[i]==0인지 확인해줌