첫째 줄에 N과 K가 주어진다. N은 250,000보다 작거나 같은 자연수이고, K는 5,000보다 작거나 같은 자연수이다. N은 항상 K보다 크거나 같다. 둘째 줄부터 N개의 수가 한 줄에 하나씩 주어진다. 입력으로 주어지는 수는 65536보다 작거나 같은 자연수 또는 0이다.
출력
첫째 줄에 정답을 출력한다. 정답은 2^63-1보다 작거나 같다.
입력 예시
10 3
3
4
5
6
7
8
9
10
11
12
출력 예시
60
풀이
세그먼트 트리를 사용해 보자. 온도를 기준으로, 카운팅하는 세그먼트 트리를 고려해보면 된다.
i번째 시점에 세그먼트 트리에는 [i-K:i]까지의 온도가 저장되어 있는 셈이다. 들어오는 값은 +1로, 나가야 할 값은 -1로 카운팅을 업데이트하면 된다.
이제 중앙값을 찾아야 할 텐데, 이는 이분 탐색을 바탕으로 진행 가능하다. 루트 노드를 기준으로 현재 탐색해야 할 순서값 idx를 잡자. 이 순서값이 왼쪽에 있는 카운팅 개수 left 내에 존재한다면, 왼쪽 서브트리를 탐색하면 된다. 그렇지 않다면 오른쪽 서브트리를 탐색하면 된다(이 때 탐색해야 할 순서값은 idx - left로 업데이트된다.)
풀이 코드
import sys
input = sys.stdin.readline
MAX = 65537
N, K = map(int, input().split())
temp_list = [int(input()) for _ in range(N)]
class SegTree :
def __init__(self, ):
self.tree = [0]*(MAX*4)
def update(self, temp, val) :
self._update(0, MAX, 1, temp, val)
def _update(self, start, end, idx, target, val) :
if target < start or target > end :
return
self.tree[idx] += val
if start == end :
return
mid = (start + end) // 2
self._update(start, mid, idx*2, target, val)
self._update(mid+1, end, idx*2+1, target, val)
def search(self) :
return self._search(0, MAX, 1, (K + 1) // 2 )
def _search(self, start, end, idx, val) :
if start == end :
return start
mid = (start + end) // 2
left = self.tree[idx*2]
if left >= val :
return self._search(start, mid, idx*2, val)
else :
return self._search(mid+1, end, idx*2+1, val-left)
segtree = SegTree()
ans = 0
for i in range(N) :
segtree.update(temp_list[i], 1)
if i > K-1 :
segtree.update(temp_list[i-K], -1)
if i >= K-1 :
ans += segtree.search()
print(ans)