Processing math: 100%

ユニークビジョンプログラミングコンテスト2023 クリスマス (AtCoder Beginner Contest 334) F,G問題メモ

ユニークビジョンプログラミングコンテスト2023 クリスマス (AtCoder Beginner Contest 334)

12/23開催なだけあって、クリスマスにちなんだ問題が多くてよき。

F - Christmas Present 2

問題

  • サンタが2次元座標上で N 人の子どもたちにプレゼントを配る
  • サンタの家は (Sx,Sy) に、子ども i の家は (xi,yi) にある
  • プレゼントを配る上での制約
    • 子ども 1,2,...,N の順に届ける
    • ソリにはプレゼントを K 個までしか積めない。補充はサンタの家でのみできる
  • サンタが自分の家から出発し、全てのプレゼントを配り終えて自分の家に戻るまでの最短距離を求めよ
  • 1KN2×105

解法

ふんわりと、以下のようなDPでできそう。

  • DP[i](イメージ)= i 軒目まで配り終えてサンタの家に戻った時の最短距離、みたいな値

K 個までしか積めない=最後に家に戻ったのが K 軒前まででないといけない。
よって、DP[i] を求めたいとき、(DP配列をセグメント木などで実装して) DP[iK]DP[i1] の最小値を得たら DP[i] が求まる、というようなことがしたい。

ただ、それだと上記の定義のままではダメ。
たとえば3軒目を訪ねるとき(DP[3] を埋めるとき)

DP[0]:  サ→①→②→③→...
        ~~                             ←DP[0]の値が示す移動

DP[1]:  サ→①→サ→②→③→...
        ~~~~~~~~~~                     ←DP[1]の値が示す移動
        
DP[2]:  サ→①→②→サ→③→...
        ~~~~~~~~~~~~~~                 ←┬小さい方がDP[2]の値が示す移動
  または                                 │
        サ→①→サ→②→サ→③→...      │
        ~~~~~~~~~~~~~~~~~~             ←┘

※サ: サンタの家

DPの示す値の最終位置がサンタの家だと、そこから3軒目に行くまでの距離がそれぞれ異なってしまうので、比較できない。

最終位置は、DP[3] を求める上では3軒目である必要がある。よって、DPを以下で定義しなおして、

  • DP[i,j]=j 軒目の後に取りに戻って、そこからは取りに戻らず j+1,...,i 軒目を順に訪れるまでの最短距離
DP[3,0]:  サ→①→②→③→...
          ~~~~~~~~~~~~~~

DP[3,1]:  サ→①→サ→②→③→...
          ~~~~~~~~~~~~~~~~~~

DP[3,2]:  サ→...→②→サ→③→...
          ~~~~~~~~~~~~~~~~~~~

これなら同条件で比較でき、DP[3,0]DP[3,2] の最小値が、3軒目に配るまでの最短距離となっている。

次、1つ進めて DP[4,] を求めたいとき、

DP[4,0]:  サ→①→②→③→④→...
          ~~~~~~~~~~~~~~~~~~

DP[4,1]:  サ→①→サ→②→③→④→...
          ~~~~~~~~~~~~~~~~~~~~~~

DP[4,2]:  サ→...→②→サ→③→④→... (一例)
          ~~~~~~~~~~~~~~~~~~~~~~~

DP[4,3]:  サ→.......→③→サ→④→... (一例)
          ~~~~~~~~~~~~~~~~~~~~~~~

DP[4,0]DP[4,2] に関しては、DP[3,0]DP[3,2] に新たに③→④の距離を加算すればよい。
DP[4,3] に関しては、DP[3,] の最小値に ③→サ→④ の距離を加算した値を新規追加すればよい。

これで4軒目までの最短距離も求められた。後は繰り返し。

実装上は i の次元は省略して破壊的に更新していくとして、 「区間加算更新」と「区間最小値クエリ」を処理できる遅延評価セグメント木でDPを実装すれば O(NlogN) で解ける。

N+1 軒目に便宜的にサンタの家を入れておけば、i=N+1 まで回した後の DP[N] が答え。

Python3

G - Christmas Color Grid 2

問題

  • H×W の、白黒で塗られたグリッドが与えられる
  • 黒を、1つだけ一様ランダムに選んで白にする
  • 縦横につながった黒を1つの連結成分とする(ナナメ不可)とき、連結成分数の期待値を求めよ
  • 1H,W1000

解法

期待値の分母は「初期状態の黒マス数」でわかりきっているので、 分子である「各黒マスを消したときの連結成分数の総和」が求まればよい。

黒マスを頂点と見なし、隣接した黒の間に辺を張ったグラフで、関節点と橋を求める。

これらは、lowlink という概念で、1回のDFSでまとめて求められる。

初期状態の連結成分数を C とする。

関節点でない場合

「関節点=そいつを消したら連結成分数が増える頂点」なので、逆に関節点でなければ連結成分は増えず C のまま変わらない。

ただしそいつが、元から1マスで1つの連結成分を構成していた場合、1減って C1 となる。

関節点の場合

関節点なら、そこから出ている辺の本数と、橋の本数を見る。

(a)全ての辺が橋なら、連結成分は「橋の本数-1」増えて  C+橋の本数-1

   ###            ###
    |
###-#-###  →  ###   ###
    |
   ###            ###


(b)そうで無い場合、橋があるなら、橋の本数分増える。 C+橋の本数

#####          #####      橋でない連結成分が1つ残ったまま、
#   |          #          橋の本数分だけ新たな連結成分ができる
###-#-###  →  ###   ###
    |
   ###            ###


(c)橋が0本の場合、必ず以下のような形となっている。
2本ずつ出る辺が、それぞれペアになってくっついている。

#####          #####
#   |          #
###-#-###  →  ###   ###
    |   #              #
    #####          #####

よって、この場合は真ん中を消すと2つに分かれ、連結成分数は1増えて C+1 となる。

(b)(c) の場合、連結成分の増減は、グリッドグラフに限った話である点に注意する。
この問題ではよいが、一般のグラフだと成り立たない。

グリッドグラフの最大次数が4であることを利用しているので、 例えば三つ葉のクローバー(♣の茎を取った形)のようなグラフの真ん中(次数6)を消すと、橋が0本と (c) と似たような状況ではあるが3つに分かれる。

一般の場合、関節点と橋の情報だけでは計算できないが、それらを求める際に計算した、DFS木とlowlinkに立ち返ればチェックできる。(公式Editorial参照)

Python3

programming_algorithm/contest_history/atcoder/2023/1223_abc334.txt · 最終更新: 2023/12/27 by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0