AtCoder Beginner Contest 353 F,G問題メモ

F - Tile Distance

問題

  • 座標平面に $1 \times 1$ の小タイルと $K \times K$ の大タイルが市松模様状に敷き詰められている(詳細は問題ページ参照)
  • $(S_x+0.5,S_y+0.5)$ から $(T_x+0.5,T_y+0.5)$ への移動コストを求めよ
  • 移動は上下左右に整数値ずつ進むことができ、新しいタイルに乗るたびにコストが1かかる
  • $1 \le K \le 10^{16}$

解法

コーナーケースの発見力が問われる問題。

まず、始点と終点が離れていたら、基本的には大タイルを通っていくのがコストを節約できる。

┼─┬─┬─┼─┴─┴─┼
│  │  │  │          │
├─┼─┼─┤          ├
│  │  │  │          │
├─┼─┼─┤          ├
│  │  │  →          │
┼─┴─┴↑┼─┬─┬─┼
│          │  │  │  │
┤          ├─┼─┼─┤
│          │  │  │  │
┤          ├─┼─┼─┤
│          │  │  │  │
┼─┬─┬─┼─┴─┴─┼

ナナメ移動をコスト2でおこなえるので、「ナナメ移動の距離は、グリッドを45度回転させてマンハッタン距離」の定石を使えば、すぐに求められる。

よって、可能性としては以下の最大17通りを試せばよい。

  • 始点と終点が小タイルで近い場合、愚直に移動
  • 以下の最大16通りの「始点・終点がともに大タイル」である移動について求め、出るまでのコストと合わせた中での最小値
    • 始点が小タイルの場合、上下左右のいずれかの大タイルにまっすぐ出た先を新たな始点とする
    • 終点が小タイルの場合、上下左右のいずれかの大タイルにまっすぐ出た先を新たな終点とする

ただし、$K=2$ の場合に限り、2つ先のタイルへ移動する場合はまっすぐ突っ切っていく方が安くなる。(これが見つけづらい)

│  │  │      │
├─┼─┤      ├
│  │  →      │
┼─┴↑┼─┬↓┼
│      │  │  →  コスト4
┤      ├─┼─┤
│      →  →  →  コスト3
┼─┬─┼─┴─┼

始点終点座標を $K$ で割ったものを $(S_x',S_y'),(T_x',T_y')$ とする。
差分 $D_x'=|S_x'-T_x'|,D_y'=|S_y'-T_y'|$ とすると、$\min(D_x',D_y')$ まではナナメ移動でおこない、 余った分 $R=\max(D_x',D_y')-\min(D_x',D_y')$ をコスト $\dfrac{3}{2}R$ でまっすぐ突っ切ることで、最小の移動となる。

Python3

G - Merchant Takahashi

問題

  • $N$ 個の町が横一列に並び、$i$ から $j$ への移動には通行料 $C \times |i-j|$ かかる
  • これから市場が $M$ 回、順番に開催され、商人の高橋君がいくつかに参加することを目論んでいる
    • $i$ 回目の市場は町 $T_i$ で行われ、高橋君が参加すると $P_i$ の儲けを得られる
    • $i$ 回目の市場の終了後にどの町にいても、高橋君は $i+1$ 回目の市場に参加できる
    • お金は潤沢に持っており、通行料が払えなくなることはない
  • 高橋君が利益(市場での儲け - 通行料)を最大化するように参加する市場を決めたとき、最大利益を求めよ
  • $1 \le N,M \le 2 \times 10^5$
  • $1 \le C \le 10^9$
  • $1 \le P_i \le 10^{13}$

解法

セグメント木DP。うまく式変形して、移動コストを織り込んだ形で管理する。

まず、素朴なDPを考えると、

  • $DP[i,j]=i$ 番目の市場終了後に、町 $j$ にいた場合の最大利益

みたいにして、$i$ 番目の市場では“もらうDP”の考え方で以下のように更新できる。

  • $DP[i,T_i] \xleftarrow[\max]{} P_i + \max_j(DP[i-1,j]-C|T_i-j|)$

(以降、破壊的に更新することとして、DPの $i$ の次元は省略する)

この $max_j$ の部分は、$T_i$ より $j$ が左か右かで場合分けすれば絶対値を外せて、

  • $\max_j(DP[j]-C|T_i-j|)$
  • $=\max(\max_{1 \le j \lt T_i}(DP[j]-CT_i+Cj), \max_{T_i \le j \le N}(DP[j]+CT_i-Cj))$
  • $=\max(-CT_i+\max_{1 \le j \lt T_i}(DP[j]+Cj), CT_i+\max_{T_i \le j \le N}(DP[j]-Cj))$

となるので、「①$DP[j]+Cj$ を載せたセグメント木」「②$DP[j]-Cj$ を載せたセグメント木」があれば、 $T_i$ を基準に左なら①、右なら②から区間最大値を得ることで、市場 $i$ の更新ができる。

これ、本番中ACが780人もいるのかぁ。。。

Python3

programming_algorithm/contest_history/atcoder/2024/0511_abc353.txt · 最終更新: 2024/05/11 by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0