N
: 입국심사대 수
M
: 인원 수
T
: k번 심사대의 심사 소요 시간
⭐️ 심사 진행 과정
- 초기 : 모든 심사대 비어있음
- 한 심사대 → 한 번에 1명의 사람만 가능
- 가장 앞의 사람
- 비어있는 심사대 보이면 거기로 가서 심사 👌
- 대기 시간 짧은 심사대로 가서 심사 👌
위와 같이 심사를 진행했을 때 걸리는 시간의 최솟값을 구하는 문제이다.
N, M의 범위가 매우 크기 때문에 시간복잡도를 최대한 줄일 수 있는 방법을 사용해야 한다.
1️⃣ 찾고자 하는 변수를 심사에 걸리는 시간이라고 정의하고, 이 시간이 M
의 사람들을 모두 심사하는데 충분한 시간인지 확인하면서 적절한 값을 찾으면 될 것이다.
→ 이를 이분탐색을 통해 찾아본다❗️
⭐️ 충분한 시간인지 확인하는 방법
- 해당 시간 내에
M
명 심사 가능한지 확인- 계산 방법
* 각 심사대마다 몇 명의 사람을 처리할 수 있는지 계산
- 해당 시간을 각 처리 시간으로 나눈 몫을 누적
- 누적값이 M보다 큰지 작은 여부를 확인
2️⃣ 위 방법을 이분 탐색으로 구현하기 위해 시작점, 끝점을 정의한다.
T
, N
, M
모두 최솟값이 1이다.T
, N
, M
의 최댓값을 기준으로 끝점을 정의한다면?for
문으로 각 시간에 접근해서 연산한다면 시간 초과가 일어날 것 같다.while문으로 이분탐색 →
for문으로 사람 수 연산 →
최종 시간복잡도
총 이 된다.
최악의 경우 이므로
이는 1초 내에 연산이 가능하다.
이분 탐색으로 심사에 걸리는 시간 탐색
1️⃣ 시작값을 1
, 마지막값을 max(T) * M
로 지정하고 중앙값을 심사에 걸리는 시간로 정의한다.
2️⃣ 시작값이 마지막값과 같아지거나 더 작아질 때까지 탐색을 지속한다.
3️⃣ 정답 저장할 변수, 심사 완료 사람 저장할 변수를 정의한다.
4️⃣ 심사 완료된 사람의 수 누적합을 계산하면서 해당 시간이 적절한지 확인한다.
5️⃣ 심사 완료 사람 수 < M
라면? → 시작값을 mid+1
로 변경해 시간 증가
6️⃣ 심사 완료 사람 수 >= M
라면? → 현재 값을 정답으로 갱신하고 마지막값을 mid-1
로 변경해 시간 감소
7️⃣ 이분 탐색이 종료될 때까지 탐색을 지속한다.
import sys
input = sys.stdin.readline
# N, M 입력
N, M = map(int, input().split())
# N번 반복해 T 입력
T = [int(input()) for _ in range(N)]
# 이분 탐색 초기값 정의
start = 1
end = max(T) * M
# 정답을 최댓값으로 초기화
answer = end
# 이분 탐색 구현
while start <= end:
mid = (start + end) // 2
# 심사한 사람 누적합 저장 변수
count = 0
# 각 시간에 대한 사람 수 누적합 계산
for t in T:
count += mid // t
# 처리 가능한 사람 수가 M보다 작으면 시간을 늘려야 한다
if count < M:
start = mid + 1
# 처리 가능한 사람 수가 M보다 크면 정답을 갱신하고 시간을 줄여본다
else:
answer = mid
end = mid - 1
# 정답 출력
print(answer)