見出し画像

【SortedList】ABC281 - E - Least Elements

未履修のデータ構造についてアウトプット。


ABC281 E問題: Least Elements (diff 1334)

提出したコード
https://atcoder.jp/contests/abc281/submissions/52265648


  • 整数$${M, K}$$と長さ$${N}$$の整数列$${A}$$が与えられる。

  • $${1 \leq i \leq N - M + 1}$$である全ての$${i}$$について$${A[i:i+M]}$$の小さい方から$${K}$$個の値の総和を出力してね。


SortedList とは

(私は中身まで理解していませんが)その名の通り「ソート順を保って要素の追加や削除ができるリスト」です。

Pythonには、c++の std::set や std::multiset に代わるものが標準で搭載されておらず、 それらが想定解の問題において難易度が跳ね上がっていました。
ABC-217 Cutting Woods が有名ですね。

それを解決してくれる  sortedcontainers というライブラリが、AtCoder の2023年8月の言語アップデートで使えるようになっていたようです。(知らなかった・・・。)

具体的な使い方、および計算量については下記の記事をご参照ください。


使って解いてみる

$${A[i:i+M]}$$の$${M}$$個の要素の集合のうち、値の小さい方から$${K}$$個の要素の集合を$${S}$$、残りの要素の集合を$${T}$$とします。

$${i}$$が +1 されるとき、集合$${S, T}$$のどちらかから$${A_{i}}$$が削除、どちらかに$${A_{i + M}}$$が追加されます。
$${S}$$の要素の変化を丁寧に追いましょう。

はじめに$${A}$$の先頭$${M}$$個の要素について答えを求めておき、差分計算をすることで解くことができます。

$${S[-1]}$$は$${S}$$の最大値、$${T[0]}$$は$${T}$$の最小値を表します。

from sortedcontainers import SortedList
N, M, K = map(int, input().split())
A = list(map(int, input().split()))

""" i = 0 の答えを求める """
B = sorted(A[:M])
S = SortedList(B[:K])
T = SortedList(B[K:M])
res = sum(S)
ans = [res]

""" i > 0 の答えを求める """
for i in range(N - M):
    T.add(A[i + M])
    if A[i] <= S[-1]:
        t = T.pop(0)
        S.add(t)
        S.remove(A[i])
        res -= A[i]
        res += t
    else:
        T.remove(A[i])
        if S[-1] > T[0]:
            s, t = S.pop(), T.pop(0)
            S.add(t)
            T.add(s)
            res += t - s
    ans.append(res)
print(*ans)

順序付き集合がないのは競プロにおける Python の弱点でもあるので、これを機に使いこなせるようになっておきたいです。

この記事が気に入ったらサポートをしてみませんか?