ABC267 D - Index × A(Not Continuous ver.) Python解答例
AtCoder Beginner Contest 267 D - Index × A(Not Continuous ver.)をPythonで解きます。
問題
問題文をAtCoderのページより引用します。
問題文
長さ
の整数列 N が与えられます。 A=(A_1,A_2,\dots,A_N) 長さ
の M の部分列(連続でなくてもよい) A に対する、 B=(B_1,B_2,\dots,B_M) の最大値を求めてください。 \displaystyle \sum_{i=1}^{M} i \times B_i 注記
数列の部分列とは、数列から
個以上の要素を取り除いた後、残りの要素を元の順序で連結して得られる数列のことを言います。 0 例えば、
は (10, 30) の部分列ですが、 (10, 20, 30) は (20, 10) の部分列ではありません。 (10, 20, 30) 制約
1 \le M \le N \le 2000 - 2 \times 10^5 \le A_i \le 2 \times 10^5 - 入力は全て整数。
解答例
動的計画法
整数列
この問題で求める値(以下、スコアと呼びます)
動的計画法で解けそうな気がしてきました。
DPテーブルの定義
DPテーブルを以下のように定義します。
初期値は以下のようになります。要素を1つも選ばなかったときスコアは0です。また、今回の問題では負の値を持つ要素が
DPテーブルの遷移は以下のようになります。
-
番目の要素を選ばなかったとき:i dp[i][j] = dp[i - 1][j] -
番目の要素を選ぶとき:i dp[i][j] = \max(dp[i][j], dp[i - 1][j - 1] + j \times A_i)
遷移についての補足
また、
答えは
実装例
Pythonによる実装例を以下に示します。
from typing import *
def main():
# 入力受け取り
N, M = map(int, input().split())
A: List[int] = list(map(int, input().split()))
# DPテーブル
dp: List[List[int]] = [[-(1 << 60) for j in range(M + 1)] for i in range(N + 1)]
# 初期条件
for i in range(N + 1):
dp[i][0] = 0
# 遷移
for i in range(1, N + 1):
for j in range(1, M + 1):
# i番目の要素を選ばないとき
dp[i][j] = dp[i - 1][j]
# i番目の要素を選ぶとき
dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + j * A[i - 1])
# 答えの出力
print(dp[N][M])
if __name__ == "__main__":
main()
実際の提出はこちら。
Discussion