EDPC N - Slimes
問題原文
問題要旨
匹のスライムが横1列に並んでいる。 番目のスライムの大きさは である。
スライムが1匹になるまで以下の操作を繰り返す。
- 隣り合うスライムをくっつけて1匹のスライムにする。このとき、くっつける前のスライムの大きさをそれぞれ , とすると、くっつけた後のスライムの大きさは になり、またコストが かかる。
スライムを1匹にするまでのコストを最小化せよ。
解法
区間dpの基礎問題らしいので解いてみた。
区間 [i, j] のスライムを1匹にする場合の最小コスト とする。
これはある を満たすスライム までで、 求めたい区間に対する答えを 区間[i, x] と 区間[x + 1, j] に対する問題へと分割することで以下再帰的に求められる。
実際のコストは、 二つの区間の答えに [i, j] の区間のスライムの大きさを足し合わせたものになる。
これは累積和で計算できる。
実装
ぎこちないったらありゃしない。dpテーブルは半開区間で持った方がよかったな。。。
更新順で頭が壊れたのでメモ化再帰で解いた。
import sys from itertools import accumulate sys.setrecursionlimit(10 ** 9) N = int(input()) A = list(map(int, input().split())) acc = [0] + list(accumulate(A)) # dp[i][j] := 区間[i, j]のスライムたちを1匹にまとめるのに必要なコスト dp = [[None] * N for _ in range(N)] for i in range(N): dp[i][i] = 0 def dfs(i, j): if j - i == 1: dp[i][j] = A[i] + A[j] return dp[i][j] if dp[i][j] is not None: return dp[i][j] ret = float('inf') for x in range(i, j): ret = min(ret, dfs(i, x) + dfs(x + 1, j) + acc[j + 1] - acc[i]) dp[i][j] = ret return ret print(dfs(0, N - 1))
感想
ちょっと理解したけどまだまだという感じ。
時間空けてときなおしてみよう。