티스토리 뷰
문제링크
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
문제설명
세준이는 크기가 N×N인 배열 A를 만들었다. 배열에 들어있는 수 A[i][j] = i×j 이다. 이 수를 일차원 배열 B에 넣으면 B의 크기는 N×N이 된다. B를 오름차순 정렬했을 때, B[k]를 구해보자.
입력
1. 배열의 크기 N이 주어진다.
2. k가 주어진다
출력
1. 일차원 배열 B를 오름차순 정렬했을 때 나오는 B[k]
제한
- 배열 A와 B의 인덱스는 1부터 시작한다.
- 구간의 점수란 구간에 속한 수의 최댓값과 최솟값의 차이이다.
- .N은 N <= 10^5 인 자연수
- k는 min(10^9, N^2)인 자연수
비슷한 문제
paramertric search를 하는 다른 문제인 랜선 자르기와 비슷한 문제였다.
랜선 자르기 같은 경우에는 주어진 N개의 랜선에서 뽑아낼 수 있는 K개의 공통 최대 랜선 길이를 출력하는 문제였다.
# https://www.acmicpc.net/problem/1654
import sys
sys.setrecursionlimit(10**7)
input, _list = sys.stdin.readline, []
N, K = map(int, input().split())
for i in range(N):
t = int(input())
_list.append(t)
_list.sort()
def parametical_search(s, e):
if s <= e:
cnt = 0
mid = (s + e) // 2
for i in range(N):
cnt += ( _list[i] // mid )
if cnt >= K:
return parametical_search(mid+1, e)
else:
return parametical_search(s, mid-1)
return e
print(parametical_search(1, _list[-1]))
문제풀이
시간 복잡도 :parametric_search O( 2 log₂ N ) * cnt갱신 O(N) => O( N log₂ N )
공간 복잡도 : parametric_search O( 2 log₂ N ) (재귀로 인한 복잡도)
위에서 살펴본 랜선 자르기에서는 공통의 최대 길이를 출력하기 위해
cnt += _list[i] // mid
와 같은 과정을 진행하며 _list[i] 번째 길이에 해당하는 랜선에서 뽑아낼 수 있는 서브 랜선의 개수를 얻어내었다.
K번째 수 같은 경우에는
cnt += min(mid // i, N)
과 같은 과정을 진행하여 cnt에 mid보다 작은 수의 개수를 저장한다.
mid보다 작은 수의 개수는 mid번째 수를 찾을 수 있게 해주고
이를 K와 비교하여 결론적으로 K번째 수를 얻을 수 있도록 해준다.
import sys # 재귀 깊이, 빠른 입출력을 위해 사용
sys.setrecursionlimit(10 ** 8)
input, print= sys.stdin.readline, sys.stdout.write
# 배열의 크기 N과, B[k]를 구하기 위한 수 K
N = int(input())
K = int(input())
def parametric_search(s,e):
# K번째 수를 찾은 경우 그 값을 출력한다.
if s >= e:
return s
# cnt : 구간 [1, N+1)에 해당하는 범위에 존재하는 수의 개수
# cnt : mid^2 이하를 가지는 수의 개수, 즉 mid^2번째(K번째) 수를 의미
# mid : A[i][j] = i * j를 성립하게 하기 위함
cnt = 0
mid = (s + e) // 2
# N과 mid // i를 진행하여 더 작은 값을 cnt에 더해준다.
# 이 과정을 통해 mid보다 작은 범위에 존재하는 수의 개수, cnt를 알 수 있다.
for i in range(1,N+1):
cnt += min(mid//i, N)
# cnt가 K보다 큰 경우 right를 작게 만듦
if cnt >= K:
return parametric_search(s, mid)
# cnt가 K보다 작은 경우 left를 크게 만듦
else:
return parametric_search(mid+1, e)
# parametric_search의 결과 출력
print(str(parametric_search(1, N*N)) + "\n")
어려웠던 점
구하기 귀찮아서 heapq의 nsmallist를 사용하여 k번째 수를 구하려고 했지만
메모리 초과를 반환했다.
그를 방지 하기 위해 gc(garbage collector)를 사용했지만
그 다음엔 시간 초과를 반환하였다.
import sys, heapq, gc
input, print = sys.stdin.readline, sys.stdout.write
N = int(input())
K = int(input())
T = 0
_list = []
heapq.heapify(_list)
for i in range(1,N+1):
for j in range(1,N+1):
heapq.heappush(_list, i*j)
gc.collect()
B = heapq.nsmallest(K, _list)
print(str(B[-1])+ "\n")
주어진 문제는 주어진 방식대로 푸는 게 낫다는 것을 깨닫게 된 시간이었다.
'알고리즘' 카테고리의 다른 글
[boj] 5557_1학년_python (0) | 2023.11.19 |
---|---|
[boj] 17626_Four squares_python (0) | 2023.11.19 |
[boj] 13397_구간 나누기2_python (0) | 2023.11.12 |
[boj] 19637_IF문 좀 대신 써줘_python (0) | 2023.11.12 |
[boj] 22944_죽음의 비_python (0) | 2023.11.10 |
- Total
- Today
- Yesterday
- 3대요소
- 내 아이피.한국
- 라그랑주 네 제곱수 정리
- Four Squares
- mysql 유저 생성
- 비교표현식
- 18352
- BOJ
- 5547
- 백준
- db 외부 접속
- 구간나누기2
- 구간 나누기
- 특정 거리의 도시 찾기
- 말이 되고픈 원숭이
- 뷰탬플릿
- 19637
- 17626
- ubuntu
- 11265
- 16918
- 2228
- onos
- 22944
- Python
- 파이썬
- 13397
- 죽음의 비
- 끝나지 않는 파티
- 5557
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |