파이썬 K번째 수(BOJ 1300)


문제

세준이는 크기가 N×N인 배열 A를 만들었다. 배열에 들어있는 수 A[i][j] = i×j 이다. 이 수를 일차원 배열 B에 넣으면 B의 크기는 N×N이 된다. B를 오름차순 정렬했을 때, B[k]를 구해보자.

배열 A와 B의 인덱스는 1부터 시작한다.


입력

첫째 줄에 배열의 크기 N이 주어진다. N은 105보다 작거나 같은 자연수이다. 둘째 줄에 k가 주어진다. k는 min(109, N2)보다 작거나 같은 자연수이다.


출력

B[k]를 출력한다.


예제 입력 1

3
7

예제 출력 1

6


📝 풀어보기


문제를 풀기 전에 이 문제의 배열을 먼저 나열해보자.

3x3

[1, 1] [1, 2] [1, 3]

[2, 1] [2, 2] [2, 3]

[3, 1] [3, 2] [3, 3]

B = [1, 2, 3, 2, 4, 6, 3, 6, 9]

B[7] = 6

이 문제는 단순히 보면

import sys
input = sys.stdin.readline

N, K = int(input()), int(input())
B = []

for i in range(1, N+1):
  for j in range(1, N+1):
    B.append(i*j)
    
print(B[K])
    

와 같은 방식으로 풀면 풀릴것같지만, 수의 범위가 크다. 단순히 반복문을 두 개 돌려서 곱한 값을 저장한 후 B의 K번째 인덱스를 찾는다면 N의 크기가 100,000 정도만 되어도 시간초과가 걸릴것이다.


이 문제는 의외로 이분 탐색으로 해결이 가능하다.

이분 탐색으로 어떤 수보다 작은 자연수의 곱(ixj)이 몇 개인지 알아내보자.

만약 어떤 수 보다 작은숫자가 몇개인지 알 수 있으면 어떤 수가 몇번째 숫자인지도 알수 있다.


예를들어 N이 3일때, 3x3배열에서 7보다 작거나 같은 수를 구하는 법을 찾아보자.

1x1 ~ 1x3 = 1, 2, 3 = 3개 (배열이 NxN이므로 최대 크기인 N을 넘을 수 없음)

2x1 ~ 2x3 = 2, 4, 6 = 3개

3x1 ~ 3x2 = 3, 6 = 2개

B = [1, 2, 3, 2, 4, 6, 3, 6]

나열해 보면 맨 처음에 본 배열과 같다는걸 알 수 있다.


위의 답은 아래와 같이 나타낼 수 있다.

7 // 1 = 3 (배열이 NxN이므로 최대 크기인 N을 넘을 수 없음)

7 // 2 = 3

7 // 3 = 2

즉, 식으로 표현해보면

N, K = int(input()), int(input())
start, end = 1, K

temp = 0
mid = (start+end) // 2
for i in range(1, N+1):
  	temp += min(mid//i, N) # 최대 N을 넘을 수 없다

이 될것이다.


위와 같은 방법으로 해당 숫자(mid) 보다 작거나 같은 숫자를 전부 찾아서 mid가 몇번째에 위치한 숫자인지 알아내면 된다.

전체코드

import sys
input = sys.stdin.readline

N, K = int(input()), int(input())
start, end = 1, K

def binary_search(start, end):
    res = 0
    while start <= end:
        temp = 0
        mid = (start+end) // 2
        for i in range(1, N+1):
            temp += min(mid//i, N)
        if temp >= K:
            res = mid
            end = mid - 1
        else:
            start = mid + 1
    return res


print(binary_search(start, end))

관심있을 포스팅