March 23, 2021 ( last updated : March 23, 2021 )
이분탐색
알고리즘
algorithm
https://github.com/sneakstarberry/
[백준] 1300번 k번째 수
솔직히 처음에는 이해를 못해서 못풀었다. 이해를 못한 부분은 다음 구문이다.
배열 A를 만들었다. 배열에 들어있는 수 A[i][j] = i×j 이다. 이 수를 일차원 배열 B에 넣으면 B의 크기는 N×N이 된다.
B의 크기가 N×N이 된다는데 무슨 소린가 했다. 알고보니 일차원 배열 B의 길이가 N×N이 된다는 것이었다. B[N×N]인 것이다. 자 그럼 이제 B[k]를 구하는 방법에 대해서 얘기해보자
골드 3문제인데 내용자체는 심플해서 놀랐다. 근데 역시나 N은 10의 5승 만큼 가능하다는 소리에서 부터 A와 B 배열을 만들어서 정렬하는 것은 안될 것 같다는 생각이 들었다. A의 배열은 안만들어 봐도 어떻게 생겼을지 알고 있기 때문에 해당 속성을 이용해야될 것이라고 생각했다.
ij | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
1 | 1 | 2 | 3 | 4 | 5 |
2 | 2 | 4 | 6 | 8 | 10 |
3 | 3 | 6 | 9 | 12 | 15 |
4 | 4 | 8 | 12 | 16 | 20 |
5 | 5 | 10 | 15 | 20 | 25 |
자 규칙이 보이는가? 보이긴 개뿔 구글링 타임이다.
농담이다. 그렇게 쉽게 포기하진 않는다.
우리가 구할 것은 B 배열의 k번째 수보다 작은 수의 숫자들을 구할 것이다. 먼저 k번째 수를 가정한다. 그리고 해당 숫자보다 낮은 수들이 몇 개인지 확인하고 확인한 결과가 k와 같다면 그 수가 k번째의 수인 것이다. 이러한 탐색을 쉽게하는 방법은 이분탐색이 좋다.
이분탐색으로 처음과 끝의 수를 정하고 예측하는 중간 값을 변화해가면서 k번째 수를 예측해 나가겠다. 먼저 이 문제에서 가장 발상이 필요한 곳은 mid로 정한 수 보다 낮은 수들이 몇개인지 확인하는 것이다. 그래프를 다시보자.
ij | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
1 | 1 | 2 | 3 | 4 | 5 |
2 | 2 | 4 | 6 | 8 | 10 |
3 | 3 | 6 | 9 | 12 | 15 |
4 | 4 | 8 | 12 | 16 | 20 |
5 | 5 | 10 | 15 | 20 | 25 |
k번째 수가 7이라고 가정해보자.
1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|
5 | 3 | 2 | 1 | 1 |
열에 따라서 위와 같이 나온다. 각각 7/i 만큼의 갯 수가 나온다는 것을 알 수 있다. 하지만 한 열에 N개를 넘을 수 없으므로 min(m/i, N )을 해줘야한다.
이해가 안가는 부분은 다음 코드를 보면서 이해한다.
#include <algorithm>
#include <iostream>
using namespace std;
long long N, K;
void solve();
int main() {
cin >> N >> K;
solve();
return 0;
}
void solve() {
long long l, h, m, ans = 1;
long long cnt = 0;
h = K + 1;
l = -1;
while (l + 1 < h) {
m = (h + l) / 2;
cnt = 0;
for (long long i = 1; i <= N; i++) {
cnt += min(N, m / i);
}
if (cnt < K) {
l = m;
} else {
ans = m;
h = m;
}
}
cout << ans;
}
Originally published March 23, 2021
Latest update March 23, 2021
Related posts :