優先度付きキュー
考え方
$K$要素のリストを管理し,- 「(リストの中で一番小さい値) < (新しい要素の値)」なら,値を置き換え,
- そうでないなら,リストを変更しない
これは,最初の要素が常に最小要素となる,優先度付きキュー(heapq
)で実現できる.
【参考】heapq --- ヒープキューアルゴリズム — Python 3.10.0b2 ドキュメント
回答例
import heapq N, K = map(int, input().split()) P = list(map(int, input().split())) q = P[:K] heapq.heapify(q) print(q[0]) for p in P[K:]: if q[0] < p: heapq.heappop(q) heapq.heappush(q, p) print(q[0])
参考
アライグマ「D問題は、「今まで見た数のうち大きい方からK個の値が入っていて、そのうち最小の数が取り出せるプライオリティーキュー」を使えば解けるのだ!」 pic.twitter.com/1HWrWzru5P
— 競技プログラミングをするフレンズ (@kyopro_friends) January 8, 2022
BIT
【参考】Binary Indexed Tree (BIT) / Fenwick Tree - 競プロはじめました考え方
ソートされた状態でリストが管理し,大きい方から$K$番目(小さい方から$i - K + 1$番目)の値を求めたい.これは,
- BITで(空想の)リストに$i$が入っているか入っていないかを 0 / 1 で管理し,
- 各ステップで,小さい方から和をとったときに$i - K + 1$となるindex(=空想のリストの要素の値)を二分探索で求める
回答例
フツーの二分探索をすると以下.BIT上の二分探索をすると高速化できる(後述).N, K = map(int, input().split()) P = list(map(int, input().split())) bit_size = N + 1 bit = [0] * bit_size def add(i, x): while i < bit_size: bit[i] += x i += i & -i def get(i): ans = 0 while i > 0: ans += bit[i] i -= i & -i return ans for i in range(K - 1): add(P[i], 1) for i in range(K - 1, N): add(P[i], 1) l, r = 0, N while r - l > 1: mid = (r + l) // 2 if get(mid) < i + 1 - K + 1: l = mid else: r = mid print(r)
BIT上の二分探索をすることで,高速化する.
N, K = map(int, input().split()) P = list(map(int, input().split())) bit_size = N + 1 bit = [0] * bit_size def add(i, x): while i < bit_size: bit[i] += x i += i & -i def get(i): ans = 0 while i > 0: ans += bit[i] i -= i & -i return ans # https://ikatakos.com/pot/programming_algorithm/data_structure/binary_indexed_tree def lower_bound(x): """ 累積和がx以上になる最小のindexと、その直前までの累積和 """ depth = N.bit_length() pos, acc = 0, 0 for i in range(depth, -1, -1): k = pos + (1 << i) if k <= N and acc + bit[k] < x: acc += bit[k] pos += 1 << i return pos + 1, acc for i in range(K - 1): add(P[i], 1) for i in range(K - 1, N): add(P[i], 1) ans, acc = lower_bound(i + 1 - K + 1) print(ans)