[ 백준 ] 3079 / 입국심사

金弘均·2021년 9월 16일
0

Baekjoon Online Judge

목록 보기
191/228
post-thumbnail

# Appreciation

/*
 * Problem :: 3079 / 입국심사
 *
 * Kind :: Binary Search
 *
 * Insight
 * - 언뜻보면 Greedy 같다
 *   + 시간에 따라 각 사람들을 심사대에 어떻게 분배하느냐가 문제인데...
 *     # 현재 t초 라고 할 때,
 *       각 심사대에 사람이 있는지 없는지, 또 있다면 끝나기까지 얼마나 시간이 남았는지
 *       이 모두를 따지는게... 쉽지가 않다
 *
 * - 일단 문제설명의 예시처럼
 *   2 6
 *   7
 *   10
 *   이 입력으로 들어왔다고 하자
 *   + 그 순간의 최선의 선택으로 사람들을 심사대에 나누는 것보다
 *     사람들이 심사받는데 걸리는 시간을 아예 처음부터 정하면
 *     그 시간안에 심사받을 수 있는 사람들의 수를 쉽게 알 수 있다!
 *     # 28초안에 6명이 모두 심사받을 수 있는가?
 *       28/7 + 28/10 = 6 => 네
 *       27초안에 6명이 모두 심사받을 수 있는가?
 *       27/7 + 27/10 = 5 => 아니요
 *       -> 시간이 증가하면 심사받을 수 있는 사람들의 수 증가
 *          시간이 감소하면 심사받을 수 있는 사람들의 수 감소
 *          이분탐색이구나...
 *
 * Point
 * - Overflow 처리가 꽤 까다롭다
 *   + 이 문제에서 가능한 최대 시간은
 *     입력으로
 *     1 10^9
 *     10^9
 *     가 주어졌을 때이며,
 *     # max(시간) = 10^18 이다
 *   + 이 문제에서 가능한 최소 시간은
 *     입력으로
 *     1 1
 *     1
 *     가 주어졌을 때이며
 *     # min(시간) = 1 이다
 *       -> 그러니 연산이 필요한 변수들은 long 으로 선언해주자
 *
 * - 사실 left=min(시간), right=max(시간) 을 정하는 것보다
 *   mid=(left+right)/2 가 주어졌을 때
 *   이 시간 내에 심사할 수 있는 사람의 수가 몇 명인지를 계산할 때
 *   Overflow 가 일어나기 쉽다
 *   + 입력으로
 *     20 10^9
 *     1
 *     1
 *     ...
 *     1
 *     1
 *     가 주어졌을 때,
 *     # mid=(1+10^18)/2=10^9 라면
 *       총 심사할 수 있는 사람의 수는 10^9 * 10*9 * 20 이다
 *       이는... long 의 범위를 벗어난다... <= 이 때문에 얼마나 틀렸는지...
 *       -> 이러한 Overflow 를 피하기 위한 방법은 또 여러가지 있을 테지만
 *          그냥 총 심사할 수 있는 사람의 수를 세다가 M 이상이 되면
 *          그때 계산을 멈추는 것이 제일 쉬운 방법처럼 보인다
 *          ^= 총 심사할 수 있는 사람의 수가 M 이상인지 아닌지만 알면 되기 때문에
 */

# Code

//
//  BOJ
//  ver.C++
//
//  Created by GGlifer
//
//  Open Source


#include <iostream>
#include <cmath>

using namespace std;

#define endl '\n'

// Set up : Global Variables
/* None */

// Set up : Functions Declaration
/* None */


int main()
{
    // Set up : I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // Set up : Input
    int N, M;
    cin >> N >> M;
    int T[N];
    for (int i=0; i<N; i++)
        cin >> T[i];

    // Process
    long l = 1, r = pow(10, 18); /* min(시간), max(시간) */
    long ans = -1;
    while (l <= r) {
        long m = (l + r) / 2;
        long cnt = 0; /* m 초 내에 심사할 수 있는 사람의 수 */
        for (int i=0; i<N; i++) {
            cnt += m / T[i];
            /* cnt 가 M 이상이면 break */
            if (cnt >= M) break; /* 이를 통해 Overflow 를 피하며
                                  * left, right 범위를 조정할 때
                                  * cnt 가 M 이상인지의 여부만 필요하기 때문에
                                  * 이후의 연산은 필요없음 */
       }

       if (cnt >= M) {
           ans = m;
           r = m-1;
       } else {
           l = m+1;
       }
   }

   // Control : Output
   cout << ans << endl;
}

// Helper Functions
/* None */
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글