ebisukeプログラミング初心者脱出黙示録

30歳を過ぎてから始めたプログラミングと競プロの記録。Pythonで取り組んでいます。Arduinoで電子工作も

AtCoder-ABC216 E - Amusement Park【Python解答例】

AtCoder Beginner Contest216のE問題についてPythonの解答例を記事にしていきます。
AtCoder Beginner Contest 216 - AtCoder


AtCoder Beginner Contest216 E - Amusement Park

E - Amusement Park

問題文

髙橋君は遊園地に遊びに行きました。
この遊園地には N 個のアトラクションがあり、i 個目のアトラクションの「楽しさ」の初期値は A i​ です。

髙橋君が i 個目のアトラクションに乗ると、以下の現象が順番に起きます。

髙橋君の「満足度」に、i 個目のアトラクションの現在の「楽しさ」が加算される。
i 個目のアトラクションの「楽しさ」が、1 減少する。
髙橋君の「満足度」の初期値は 0 です。髙橋君はアトラクションに合計 K 回まで乗ることができます。
最終的な髙橋君の「満足度」の最大値はいくつですか?

なお、髙橋君の「満足度」はアトラクションに乗ること以外で変化しません。

制約

・1≤N≤10 ^5
・1≤K≤2×10 ^9
・1≤A i​ ≤2×10 ^9
・入力は全て整数

解答例

N, K = map(int,input().split())

A = list(map(int, input().split()))

# 降順で最後の要素が0
A.sort(reverse=True)
A.append(0)

# 搭乗回数
k = 0
# 合計満足度
score = 0
# 搭乗回数が余るかどうか
flag = True

for i in range(N):
    # 次の要素と一致するまでに必要な搭乗回数
    tmp = (i + 1) * (A[i] - A[i+1])
    # tmpがKより大きければberak
    if k + tmp > K:
        break
    # スコアとkを更新
    score += (i + 1) * (A[i]*(A[i]+1) - (A[i+1])*(A[i+1]+1)) // 2
    k += tmp
else:
    flag = False

Kが0になるまでのスコア計算
if flag:
    div = (K-k) // (i+1)
    mod = (K-k) % (i+1)
    tmp = A[i]
    
    score += (i+1) * (tmp*(tmp+1) - (tmp-div)*(tmp-div+1))//2
    score += mod * (tmp-div)

print(score)

解説

乗るごとに満足度が1減るアトラクションがN個あり、K回搭乗できるときの満足度の最大値を答える問題です。

満足度のリストAは降順でソートしてから末尾に0を足します。

次のループで満足度の大きいアトラクションから搭乗回数kが制約のKを超えない範囲で乗り続けたときの満足度を貪欲に計算していきました。

i番目の要素からi+1番目の要素の満足度と一致するまで乗るとき、搭乗回数は(i + 1) * (A[i] - A[i+1])です。
満足度は1からA[i]までの和から、1からA[i+1]までの和を引いた値にi+1をかけた値です。

1からNまでの和についてはこちらを参照
ebisuke33.hatenablog.com

搭乗回数がKを超える場合は、ちょうどKになるまで満足度を足し合わせていきました。

最終的に求まったscoreを出力すればACでした。



ABC216の関連記事はこちら
ebisuke33.hatenablog.com
ebisuke33.hatenablog.com