AtCoderBeginnerContest270 D問題 400点 「Stones」
AtCoderBeginnerContest270 D 問題 400 点 「Stones」
問題概要
制約
解法
貪欲にやっていくことがなんとなく悪いことはわかる。自分ができるだけ取りつつ,相手にはできるだけ取らせないようにしなければならないので,このような問題には貪欲法を用いることはできない。凡例は解説にあるので確認すること。
ここで,DP を以下のように定義する。
$dp[i]$: 石が$i$個あったときの先手が得られる石の最大値
このように定義すると,後手の計算も実は同時にできることがわかる。先手が$A_j$個石を取ったときの後手は最大で$dp[i-A_j]$個の石を獲得できることになる。
したがって,更新式は以下のようになる \(dp[i] = max(dp[i], i - dp[i-A_j]\) ここで,$i$は現在の石の個数,$dp[i-A_j]$は後手が得られる石の数の最大値となる。これを石が 0~N 個あった場合を昇順に計算することで,石が N 個あったときの先手が得られる石の最大値$dp[N]$を求めることができる。
計算量は,DP テーブルの更新に$\mathcal{O}(N)$,最大値を求めるのに$\mathcal{O}(1)$なので,全体の計算量は$\mathcal{O}(N)$で求めることができる。
お気持ち
AC コード
N, K = map(int, input().split())
A = list(map(int, input().split()))
A.sort()
dp = [0] * (N + 1)
for i in range(1, N + 1):
for a in A:
if i - a >= 0:
# dp[i-a]:i 個の石があって,
# 先手がi個取ったときに後手が取れる石の数
dp[i] = max(dp[i], i - dp[i - a])
print(dp[N])