반응형

[Silver I] 보석 상자 - 2792

문제 링크

성능 요약

메모리: 131744 KB, 시간: 388 ms

분류

이분 탐색(binary_search), 매개 변수 탐색(parametric_search)

문제 설명

보석 공장에서 보석 상자를 유치원에 기증했다. 각각의 보석은 M가지 서로 다른 색상 중 한 색상이다. 원장 선생님은 모든 보석을 N명의 학생들에게 나누어 주려고 한다. 이때, 보석을 받지 못하는 학생이 있어도 된다. 하지만, 학생은 항상 같은 색상의 보석만 가져간다.

한 아이가 너무 많은 보석을 가져가게 되면, 다른 아이들이 질투를 한다. 원장 선생님은 이런 질투심을 수치화하는데 성공했는데, 질투심은 가장 많은 보석을 가져간 학생이 가지고 있는 보석의 개수이다. 원장 선생님은 질투심이 최소가 되게 보석을 나누어 주려고 한다.

상자에 빨간 보석이 4개 (RRRR), 파란 보석이 7개 (BBBBBBB) 있었고, 이 보석을 5명의 아이들에게 나누어 주는 경우를 생각해보자. RR, RR, BB, BB, BBB로 보석을 나누어주면 질투심은 3이 되고, 이 값보다 작게 나누어 줄 수 없다.

상자 안의 보석 정보와 학생의 수가 주어졌을 때, 질투심이 최소가 되게 보석을 나누어주는 방법을 알아내는 프로그램을 작성하시오.

입력

첫째 줄에 아이들의 수 N과 색상의 수 M이 주어진다. (1 ≤ N ≤ 109, 1 ≤ M ≤ 300,000, M ≤ N)

다음 M개 줄에는 구간 [1, 109]에 포함되는 양의 정수가 하나씩 주어진다. K번째 줄에 주어지는 숫자는 K번 색상 보석의 개수이다.

출력

첫째 줄에 질투심의 최솟값을 출력한다.

풀이방법

질투심의 최솟값을 구하기 위해서는 값으로 나올 수 있는 가진 보석의 최소, 최대값(1, max(jewel)을 설정하여 이분탐색을 통해 빠르게 답을 찾을 수 있다.

1. 이분 탐색의 기준은 탐색값(mid)은 질투심으로 두고, 가진 모든 보석들을 색상이 같은 것들끼리 묶어 질투심으로 나눈 몫(나누어 떨어지지 않으면 올림(+1)들의 합은 해당 질투심 값의 학생 수(div)가 된다.

2. 이 학생 수(div)가 기존의 학생 수(n)보다 크다면, 학생 수를 더 줄여줘야 하므로 질투심으로 나눈 몫을 감소시키기 위해서 질투심을 증가시킨다.

3. 반대의 경우, 질투심을 감소시킨다.

4. start가 end보다 크면 while문은 종료. 즉, while문이 끝난 즉시 학생 수(n)와 맞아떨어지는 질투심의 최솟값(start)을 구할 수 있다.

import sys, math # 빠른 입력, 올림(ceil) 사용을 위한 라이브러리 호출
input = sys.stdin.readline # 빠른 입력

jewel = [] # 보석들
n, m = map(int,input().split()) # 학생 수, 보석의 수
for _ in range(m): # 같은 색상의 보석 개수
    jewel.append(int(input()))

start, end = 1, max(jewel) # 받을 수 있는 질투심의 최솟값과 최댓값

while start <= end: # 이분 탐색

    mid = (start + end) // 2 # 중간 값(질투심)
    div = 0 # 현재 질투심으로 구한 학생 수

    for color in jewel: # 같은 색상 보석들 가져오기
        div += math.ceil(color/mid) # 학생 수 구하기
    
    if div > n: # 학생 수가 필요한 학생 수보다 더 많아진다면 
        start = mid + 1 # 질투심 증가
    else:
        end = mid - 1 # 질투심 감소
print(start)

+ Recent posts