AtCoder Beginner Contest 422 D,F,G問題メモ

AtCoder Beginner Contest 422

大会の決勝を兼ねていたため、珍しくお昼の開催。海外勢には参加しづらい時間帯のためか、参加者数は若干少なめ?

D - Least Unbalanced

問題文

  • $N$ を正整数とします。長さ $2^N$ の非負整数列 $A=(A_1, A_2, \dots, A_{2^N})$ の アンバランスさ を次の操作によって得られる非負整数値として定義します。
    • はじめ、$X=0$ とする。
    • 次の一連の操作を $N$ 回行う。
      • $X$ を $\max(X, \max(A) - \min(A))$ に更新する。ここで $\max(A)$ および $\min(A)$ は数列 $A$ の最大値と最小値を意味する。
      • 先頭から順に $2$ つずつ要素を組にして、それらの和を並べることでできる長さが $A$ の半分の数列を、新たな $A$ とする。すなわち、$A \gets (A_1 + A_2, A_3 + A_4, \dots, A_{\vert A \vert - 1} + A_{\vert A \vert})$ とする。
    • 最終的な $X$ をアンバランスさとする。
  • 例えば $N=2, A=(6, 8, 3, 5)$ は以下の手順によりアンバランスさが $6$ であるとわかります。
    • はじめ、$X=0$ である。
    • 1 回目の一連の操作は次の通りである。
      • $X$ を $\max(X, \max(A) - \min(A)) = \max(0, 8 - 3) = 5$ に更新する。
      • $A$ を $(6+8, 3+5) = (14, 8)$ とする。
    • 2 回目の一連の操作は次の通りである。
      • $X$ を $\max(X, \max(A) - \min(A)) = \max(5, 14 - 8) = 6$ に更新する。
      • $A$ を $(14 + 8) = (22)$ とする。
    • 最終的に $X=6$ となる。
  • 非負整数 $K$ が与えられます。長さ $2^N$ の非負整数列であって総和が $K$ であるものの中で、アンバランスさが最小値を取る数列を構成してください。

制約

  • $1 \leq N \leq 20$
  • $0 \leq K \leq 10^9$
  • $N, K$ は整数

解法1

区間和のセグメント木を、上から半分ずつにして埋めていくイメージ。

N=3  K=35
  |--------------35---------------|
  |------18-------|------17-------|
  |---9---|---9---|---9---|---8---|
  |-5-|-4-|-5-|-4-|-5-|-4-|-4-|-4-|

$K$ が $2^N$ で割り切れるならアンバランスさは $0$。 それ以外の場合、$1$ が達成できる。

解法2

とりあえず $K/2^N$ の商の部分は均等に配って、端数の $K \mod 2^N$ をどう分配するかの話になる。
以下の順で配っていくのが良い。

N=4
  0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
    1
                                            2
                        3                                       4
              5                   7                   6                   8
         9         13        11        15        10        14        12        16

これは、よく見ると「2進数の $0000,0001,0010,0011,0100,...$ を、文字列として逆から見た順」となっている。
その順で端数分を配ると答えとなる。

または、$A=[0000]$ からはじめて、以下のように端数を配っていくことでもよい。

  • $A$ のそれぞれに1bit目を立てたindexに配り、$A$ にそれらを加える→$A=[0000,1000]$
  • $A$ のそれぞれに2bit目を立てたindexに配り、$A$ にそれらを加える→$A=[0000,1000,0100,1100]$
  • $A$ のそれぞれに3bit目を立てたindexに配り、$A$ にそれらを加える→$A=[0000,1000,0100,1100,0010,...]$

Python3

F - Eat and Ride

問題文

  • $N$ 頂点 $M$ 辺の連結無向グラフがあります。
  • 頂点には頂点 $1,$ 頂点 $2,\ldots,$ 頂点 $N$ と番号付けられており、$i$ 番目 $(1\le i\le M)$ の辺は頂点 $u _ i$ と頂点 $v _ i$ を結んでいます。
  • $i=1,2,\ldots,N$ について次の問題を解いてください。
    • はじめ、高橋くんの体重は $0$ です。
    • 高橋くんは、車に乗って頂点 $1$ に訪れ、頂点 $i$ に向かって移動を行います。
    • 高橋くんが頂点 $v\ (1\le v\le N)$ に訪れるとき、高橋くんの体重は $W _ v$ だけ増加します。
    • 高橋くんが乗っている車は辺に沿って移動することができます。
    • 高橋くんが辺を通過するとき、そのときの高橋くんの体重を $X$ として、車は燃料を $X$ 消費します。
    • 高橋くんが頂点 $i$ にたどり着くために消費する燃料の量の最小値を求めてください。

制約

  • $1\le N\le5000$
  • $1\le M\le5000$
  • $1\le W _ i\le10 ^ 9\ (1\le i\le N)$
  • $1\le u _ i\le v _ i\le N\ (1\le i\le M)$
  • 与えられるグラフは連結
  • 入力はすべて整数

解法

Dijkstraの改良だが計算量が間に合う証明はできていない。
実装してみたら意外と高速に通ったが、テストケースに助けられているだけなのかは不明。

この問題の難しい点は、「$1→v$ の最適な経路」と 「$1→(v経由)→u$ の最適な経路の $1→v$ の部分」が、同じとは限らない点にある。

①-------②-------⑦--⑧
 `-③--④--⑤--⑥-'

i  1   2  3  4  5  6  7  8
W  1  10  1  1  1  1  1  1

⑦への燃料は、
①→②→⑦の12が最適だが、その時の体重は12
①→③→...→⑦の経路を取れば、燃料は15かかるが、体重は6

⑧までの燃料は、
①→②→⑦→⑧だと増えた体重が重くかかり、24
①→③→...→⑦→⑧だと21で逆転する。

⑦に燃料12で到達した後、別経路で燃料15で到達しても、その後の探索を広げる必要があるということになる。

ただし「燃料・体重のいずれも、過去に訪れた場合より悪い」場合は、さすがにそれ以降の頂点も最適にはなり得ない。
少なくともどちらかが過去に訪れたときより小さいなら、探索を広げればよい。

燃料を第一基準としてDijkstraをおこなうと、ある頂点に訪れるのは「消費燃料が小さい順」であると保証される。
よって、通常のDijkstraにおけるコスト(今回は燃料)の他に 「$w_v:=$ これまでに頂点 $v$ を訪れたときの最小体重」も記録しておき、 現在体重がそれを下回る場合のみ、探索を広げることをすればよい。

Python3

解法2

公式Editorialの、計算量保証のある解法。

「$x$ に到着するまでに通る辺数」を固定すると、 ある頂点 $v$ に訪れたときの全体にかかるコストは $W_v \times 残り辺数$ となる。

x までに4辺通るとすると

  ①----> (a) ----> (b) ----> (c) ----> (x)

W1×4    Wa×3     Wb×2     Wc×1      ←この合計が、このパスのコスト

1つのパスの中で同じ頂点を訪れる意味は無いので、通る辺数は最大 $N-1$ に限られる。

よって、それぞれの頂点を $(頂点番号, 残り辺数)$ とし、 $(u,i)→(v,i-1)$ にコスト $W_u \times i$ の辺を張ればよい。

頂点数、辺数が高々 $N$ 倍となるので、$N^2$ 頂点、$MN$ 辺のDijkstraとして解ける。

G - Balls and Boxes

問題文

  • 正整数 $N, A, B, C$ が与えられます。
  • 問題 $1$ および問題 $2$ をそれぞれ解いてください。
  • 問題1
    • $N$ 個のボールがあります。ボール同士は区別できません。
    • 次の条件を満たすように、区別できる箱 $1,2,3$ に全てのボールを入れる方法の個数を $998244353$ で割った余りを求めてください。
      • 箱 $1$ に入っているボールの個数は $A$ の倍数である。
      • 箱 $2$ に入っているボールの個数は $B$ の倍数である。
      • 箱 $3$ に入っているボールの個数は $C$ の倍数である。
  • 問題2
    • $1$ から $N$ までの番号のついた $N$ 個のボールがあります。ボール同士は区別できます。
    • 次の条件を満たすように、区別できる箱 $1,2,3$ に全てのボールを入れる方法の個数を $998244353$ で割った余りを求めてください。
      • 箱 $1$ に入っているボールの個数は $A$ の倍数である。
      • 箱 $2$ に入っているボールの個数は $B$ の倍数である。
      • 箱 $3$ に入っているボールの個数は $C$ の倍数である。

制約

  • $1 \leq N \leq 3 \times 10^5$
  • $1 \leq A \leq 3 \times 10^5$
  • $1 \leq B \leq 3 \times 10^5$
  • $1 \leq C \leq 3 \times 10^5$
  • 入力される値は全て整数

解法

知ってたら一発の問題。以下のサイトにズバリの解法がある。

問題1は、取れる値に制約($A,B,C$ の倍数であること)がある上での $N$ の分割数である。
以下の3つの形式的冪級数の積をとり、$x^N$ の項の係数が答えとなる。

  • $x^0+x^A+x^{2A}+...$
  • $x^0+x^B+x^{2B}+...$
  • $x^0+x^C+x^{2C}+...$

問題2は、たとえば箱1,2,3に $p,q,r$ 個入れた場合のボールの対応付け方は、$\dfrac{N!}{p!q!r!}$ 個ある。
よって、これも係数に折り込んでから畳み込めばよい。最後に $x^N$ の項の係数の $N!$ 倍が答えとなる。

  • $x^0+ \dfrac{1}{A!}x^A+\dfrac{1}{(2A)!}x^{2A}+...$
  • $x^0+ \dfrac{1}{B!}x^B+\dfrac{1}{(2B)!}x^{2B}+...$
  • $x^0+ \dfrac{1}{C!}x^C+\dfrac{1}{(2C)!}x^{2C}+...$

Python3

programming_algorithm/contest_history/atcoder/2025/0907_abc422.txt · 最終更新: by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0