문제의 풀이가 너무 이해가 안가서 아주 자세하게 알아보았습니다.
이분탐색의 시작값(start
)은 모든 수가 같다는 가정 하에 0이다.
이분탐색의 끝값(end
)은 배열의 최댓값에서 최솟값을 뺀 값이다.
(구간의 차이가 가장 큰 값을 이분탐색의 끝값으로 시작한다.)
이분탐색을 통해 중간값(mid
)를 구한다.
중간값은 구간의 점수의 최댓값-최솟값을 한 것 중 최댓값의 마지노선이다.
이 중간값이 최적의 값인지를 계산하는 함수(is_valid()
)를 실행한다.
mid
)으로 새로운 구간들을 구한다.min_num
)와 최대(max_num
)를 초기화한다.count
)를 1로 초기화한다.count
)가 증가하기 때문에 count + 1
을 한다.num
)부터 시작되기 때문에 최솟값(min_num
)과 최댓값(max_num
)을 현재 수로 초기화 한다.mid
)는 최적의 값이 아니기 때문에 False
를 반환한다.True
를 반환한다.현재 중간값(mid
)이 최적의 값(is_valid() == True
)인 경우, 현재 중간값을 결과값(ans
)에 저장하고 끝값(end
)을 mid - 1
로 변경한다.
(현재 중간값으로 m개 이하의 수를 만드는 것이 가능해도, 그 이하에서 최적화된 수가 나올 수 있기 때문)
최적의 값이 아닌(is_valid() == False
) 경우, 구간이 m개보다 많다는 뜻이기 때문에 시작값(start
)을 mid + 1
로 변경한다.
즉, is_valid()
가 True
라는 뜻은 현재의 중간값(mid
)으로 m개 이하의 구간이 생기기 때문에, 중간값(mid
)는 적정한 값이다.
-> 이 중간값(mid
) 중 최솟값을 구하는 것이 문제의 요구사항이다.
-> 중간값(mid
)을 줄이고 다시 구간나누기 실행
is_valid()
가 Flase
라는 뜻은 현재의 중간값(mid
)으로 m개 초과의 구간이 생기기 때문에, 중간값(mid
)이 너무 작다는 뜻이다.
-> 한 구간의 최댓값 - 최솟값의 마지노선이 작아 구간이 많이 생긴다.
-> 중간값(mid
) 증가
# BOJ
# G4 - 13397(구간 나누기 2)
import sys
input = sys.stdin.readline
n, m = map(int, input().split())
nums = list(map(int, input().split()))
start, end = 0, max(nums) - min(nums)
ans = 0
def is_valid(mid):
min_num = max_num = nums[0]
cnt = 1
for num in nums:
min_num = min(min_num, num)
max_num = max(max_num, num)
if max_num - min_num > mid:
cnt += 1
min_num = max_num = num
if cnt > m:
return False
return True
while start <= end:
mid = (start + end) // 2
if is_valid(mid):
ans = mid
end = mid - 1
else:
start = mid + 1
print(ans)