N
: 아이들 수 ()
M
: 놀이기구 종류 ()
times
: 운행 시간 ()
N
명의 아이들이 각각 다른 운행 시간을 가진 M
개의 놀이기구를 탄다고 할 때, 마지막 아이가 탈 놀이기구 번호를 출력하는 문제이다.
⭐️ 놀이기구 타는 방법
- 서 있는 순서대로 놀이기구 탑승
- 여러 놀이기구 비어있다면 더 적은 번호의 놀이기구부터 탑승
N의 크기가 매우 크기 때문에 순차적으로 찾는 방식으로 푼다면 시간 초과가 발생할 것이다.
→ 시간복잡도를 줄이기 위해 이분탐색 활용한 방법으로 문제를 푼다.
먼저 탐색이 필요한 경우, 필요하지 않은 경우를 각각 고려해준다.
N ≤ M이라면 이분탐색을 하지 않고도 N
번 놀이기구라는 것을 바로 구할 수 있다.
그렇지 않다면 이분탐색을 진행해서 구해야 한다.
이 문제는 운행 시간이 다른 것이 핵심이기에 마지막 순서의 아이가 놀이기구에 타는 시간을 구하는 것을 목표로 탐색을 진행한다.
이분탐색 구현
left, right = 0, max(times) * N
mid
: 마지막 아이가 놀이기구 타는 시간left
가 right
와 같거나 커지는 경우mid
시간 내에 모든 아이들이 놀이기구를 탈 수 있는지 계산M
초기화 (N > M이므로)N
→ right
감소 (시간 줄여보기)N
→ left
증가 (시간 늘려보기)마지막 아이가 탄 놀이기구 찾기
이분탐색 →
탄 시간 계산 →
탄 놀이기구 확인 →
최종 시간복잡도
로 최악의 경우 이 되어 2초 안에 계산 가능하다.
이분탐색으로 마지막 아이가 탄 시간 계산
import sys
input = sys.stdin.readline
# N, M 입력
N, M = map(int, input().split())
# 운행시간 입력
times = list(map(int, input().split()))
# 놀이기구 번호 바로 구할 수 있는 경우
if N <= M:
print(N)
else:
# 0분부터 최대 시간까지 탐색
left, right = 0, max(times) * N
# 이분 탐색 구현
while left < right:
mid = (left + right) // 2
# mid까지 놀이기구를 탄 아이들 수 계산
rides = M
for time in times:
rides += mid // time
# 탑승한 아이가 N명을 초과하면 시간 감소
if rides >= N:
right = mid
else:
left = mid + 1
# 마지막 아이가 탄 놀이기구 찾기
rides = M
for time in times:
rides += (left - 1) // time
for i, time in enumerate(times):
# 해당 놀이기구가 정확히 left 시점에 비었다면
if left % time == 0:
rides += 1
# 마지막 아이가 탑승한 경우 출력
if rides == N:
print(i + 1)
break