본문 바로가기

운동하는 개발자/알고리즘, 코딩테스트

Beakjoon] K번째 수 (백준 1300 코테) - 탐색

728x90


🅰️문제주소 : https://www.acmicpc.net/problem/1300

 

1300번: K번째 수

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

www.acmicpc.net

 


🚩문제 

 

 

🪡풀이 

 - 문제 그대로 2차원 배열을 만들고 정렬을 시키면 시간복잡도가 N^2으로 초과해버린다.
 - A[i][j] = i×j 배열에서 두 가지의 규칙을 찾아야 한다.
  1) 해당배열은 k번째 값은 k의 값을 넘지 못한다. (3x3배열에서 마지막 인덱스의 값이 9이므로)
  2) 한 행에서 '중앙값을 행으로 나눈 값' vs '열의 수' 둘 중 작은 수는 해당 행에서 중앙값보다 작거나 같은 수의 개수가 된다. 따라서 이 값을 모든 행에서 구한 뒤 합산한 뒤 K와 비교하면 K번째 값이 현재보다 앞쪽에 있는지, 뒤쪽에 있는지 알 수 있다. 
 - 위 규칙에 의해서 '작거나 같은 수의 개수'의 합 값이 K보다 작으면 K값은 더 뒷쪽에 있으므로 시작인덱스 값을 중앙값+1으로 변경한다.
 - 반대로 '작거나 같은 수의 개수'의 합이 K보다 크거나 같으면 현재 K의 값을 찼았거나 K의 값이 더 앞쪽에 있다는 뜻이므로 임시로 정답에 중앙값을 넣어준 뒤 종료인덱스를 중앙값-1로 변경하고 이진탐색이 종료될 때까지 계속한다. 

 

☕코드는 아래 숨김

더보기

#include <iostream>
#include <vector>
#include <math.h>
int main() {
	std::ios::sync_with_stdio(false);
	std::cout.tie(0);
	std::cin.tie(0);

	int N, k;

	std::cin >> N;
	std::cin >> k;

	int start = 1;
	int end = k;
	int result = 0;
	while (start <= end) {
		int mid = (start + end) / 2;
		int temp_sum =0;
		for (int i = 1; i <= N; ++i) {
			temp_sum += std::min(N, mid / i);
		}
		if (temp_sum < k) {
			start = mid + 1;
		}
		else {
			result = mid;
			end = mid - 1;
		}
	}

	std::cout << result;

	return 0;
}

 

💡알게 된 것 

 - A[i][j] = i×j 배열에서 두 가지의 규칙
  1) 해당배열은 k번째 값은 k의 값을 넘지 못한다. (3x3배열에서 마지막 인덱스의 값이 9이므로)
  2) 한 행에서 '중앙값을 행으로 나눈 값' vs '열의 수' 둘 중 작은 수는 해당 행에서 중앙값보다 작거나 같은 수의 개수가 된다. 따라서 이 값을 모든 행에서 구한 뒤 합산한 뒤 K와 비교하면 K번째 값이 현재보다 앞쪽에 있는지, 뒤쪽에 있는지 알 수 있다. 

이걸 모르면 탐색이고 뭐고 시작도 할 수 없다...


 

728x90