かんプリンの学習記録

勉強したことについてメモしています. 主に競技プログラミングの問題の解説やってます.

ABC163 E - Active Infants

問題はこちら

問題概要

{2\le N\le 2000}人の幼児が左右一列に並んでおり, 左から{i}番目の幼児の活発度は{1\le A_i\le 10^9}である. 幼児の順番を好きに並び替える. はじめ左から{x}番目に並んでいた幼児が左から{y}番目に移動するとき,うれしさが{A_x×|x−y|}だけ生じる. 幼児のうれしさの合計の最大値を求めよ.

思考の流れ

まず, 活発度の高い幼児から順に一番遠いところに入れるgreedyを思い付くが, 入力例2などで不正解となる.
なぜダメかというと{6}を右に入れたせいで{2}つの{5}が一つ左にずれてうれしさが減少したから.
この場合, {6}を左端に入れるべきだった.

{\downarrow}

大きい順に入れていくのはいいとして, 左右どちらに入れるのがよいか. 全探索しようとすると{2^N}通り試す必要がある.
左右から数字が埋まっていく. ある数字を左右どちらに入れるか考えるときに, 今まで入れた数字がそれぞれどこにあるかは関係なく, 左右の数字がどこまで埋まっているかがわかればよさそう.

{\downarrow}

DPをする. {dp[i][j]}を「左から{i}番目, 右から{j}番目までが埋まっているときの最大値」とすると更新式は, {B_i}を「活発度が大きい方から{i}番目の幼児の活発度」, {t_i}を「活発度が大きい方から{i}番目の幼児の元の位置」として

{dp[i][j]=\max(dp[i-1][j]+B_{i+j}×(t_{i+j}-i),dp[i][j-1]+B_{i+j}×(N-j+1-t_{i+j}))}

ただし, {i+j}の小さい方からDPを行う.

証明

なぜ大きい方から端に埋めていくのがいいのか?
図1のような状況を考えた時, 図2のようにすることでうれしさの合計を増加させることができる.

f:id:kanpurin:20200421011539p:plain
図1
f:id:kanpurin:20200421011735p:plain
図2

これは, 「元の位置より右にずらすものは, 元の位置より左にずらすものよりも, ずらした後の位置が必ず右にある」ことを意味している.

また, {a\gt b}のとき図3のような状況を考えると, 図4のようにすることで, うれしさの合計を増加させることができる.

同様に, {a\lt b}のとき図4のような状況を考えると, 図3のようにすることで, うれしさの合計を増加させることができる.

f:id:kanpurin:20200421012232p:plain
図3
f:id:kanpurin:20200421012449p:plain
図4

以上のことから端から大きい順に埋めていくのが最適となる.

提出プログラム

https://atcoder.jp/contests/abc163/submissions/12180393

感想

制約がDPっぽかったがわからなかった. 解説書いてみると, 普通の流れで解けたと思って反省.