문제후기
- 해당 조건(N은 10^5보다 작거나 같은 자연수이다. 둘째 줄에 k가 주어진다. k는 min(10^9, N^2)보다 작거나 같은 자연수이다)을 확인하고 완전탐색을 하게되면 시간초과가 발생할 것을 예상했습니다. 알고리즘은 이분탐색(logN)을 활용해야겠다고 생각하게 됐습니다
- 배열에 있는 값을 어떻게 하면 이분탐색으로 할 수 있을지 고민하는데 오래걸렸습니다. 같이 문제푸는 사람과 이야기를 하다가 몫과 나머지를 활용하면 어떻게 되지 않을까라는 말이 나와 몫을 활용하기 시작했습니다.
- 몫을 활용해서 해당 숫자가 정답을 만족하게 되는 경우 마지막값(end)을 땡기고 만족하지 않는 경우 시작값(start)을 미루는 방식으로 진행했습니다.
자세한 예시를 들어보면
문제에서 제시한 예시 3으로 보여드리겠습니다. 3을 2차배열로 만들게 되면 아래와 같아집니다.
1 | 2 | 3 |
2 | 4 | 6 |
3 | 6 | 9 |
위의 도표를 봤을때 찾는 방식은 행의 첫번째 값을 기준으로 나누는 것입니다. 중간값은 시작(1), 마지막(9)이므로 5입니다.
- 첫 번째 줄은 1번 값이 1. 그러므로 중간값을 1로 나누면 5//1 = 5이므로 N 3보다 크므로 5보다 작은값은 3개.
- 두 번째 줄은 1번 값이 2. 그러므로 중간값을 2로 나누면 5//2 = 2이므로 N 3보다 작으므로 5보다 작은값은 2개.
- 세 번째 줄은 1번 값이 3. 그러므로 중간값을 3로 나누면 5//3 = 1이므로 N 3보다 작으므로 5보다 작은값은 1개.
- 전체 총 6개가 5보다 작습니다.
- 시작값과 마지막값을 조정하면서 위의 과정을 반복해 K번째 값을 찾으면 됩니다.
문제링크
from sys import stdin
# Input 값
N = int(stdin.readline())
K = int(stdin.readline())
# 이분탐색 시작값과 마지막 값.
start, end = 1, N ** 2
answer = 0 # 정답값
# 이분탐색 실행.
while start <= end:
middle = (start + end) // 2
count = 0
# 해당 값이 N이상으로 나눠지는지, N개인지, 그보다 적은지 판단
# middle보다 작은 값 갯수 카운팅
for i in range(1, N+1):
count += min(middle//i, N)
# 만약 갯수가 K보다 많거나 작으면 end값 땡겨서 범위 축소
if count >= K:
end = middle - 1
answer = middle
# 만약 갯수가 K보다 적으면 start값 땡겨서 범위 축소
else:
start = middle + 1
print(answer)
print(start)
'백준' 카테고리의 다른 글
[백준] 가장 긴 바이토닉 부분 수열 -Python (0) | 2021.01.18 |
---|---|
[백준] RGB거리 -Python (0) | 2021.01.14 |
[백준] 욕심쟁이 판다 -Python (0) | 2021.01.12 |
[백준] 절대값 힙 -Python (0) | 2021.01.10 |
[백준] 미확인 도착지 -Python (0) | 2021.01.09 |