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

C - Reindeer and Sleigh 2

問題文

  • $N$ 匹のトナカイと $1$ 個のソリがあります。$i$ 番目のトナカイは重さが $W_i$ で力は $P_i$ です。
  • 各トナカイについて、「ソリを引く」または「ソリに乗る」のいずれかを選びます。
  • ただし、ソリを引くトナカイの力の総和が、ソリに乗るトナカイの重さの総和以上でなければなりません。
  • 最大で何匹トナカイをソリに乗せることができますか?
  • $T$ 個のテストケースが与えられるので、それぞれについて答えを求めてください。

制約

  • $1\leq T\leq 10^5$
  • $1\leq N\leq 3\times 10^5$
  • $1\leq W_i,P_i\leq 10^9$
  • 入力は全て整数
  • $1$ つの入力ファイルに含まれる $N$ の総和は $3\times 10^5$ 以下

解法

Cにしてはむずくない?

ソリに乗っているトナカイの重量の総和を $X$、そりを引くトナカイの力の総和を $Y$ とする。

まず、とりあえず全てソリに乗せる。
この時、$X=\sum_i W_i, Y=0$ である。

引く力が重量以上にならないといけない。つまり、$X-Y \le 0$ にならないといけない。
ソリを降りて引く側に回るトナカイを増やしていく。

トナカイ $i$ を引く側に回すと「重量は $W_i$ 減り、引く力は $P_i$ 増える」ので、 $X-Y$ は、差し引き $W_i+P_i$ だけ小さくなる。

なるべく引く側のトナカイを少なくしたいので、$W_i+P_i$ が大きい方から引く側に回ってもらうのが最適となる。
この累積合計が、初期値の $X-Y(=\sum_i W_i)$ 以上になったら、それが引く側のトナカイの最小数となる。

Python3

E - Sort Arrays

問題文

  • $N+1$ 個の数列 $A_0, A_1, \ldots, A_{N}$ があります。$A_i$ は以下のように定義されます。
    • $A_0$ は空の数列
    • $A_i\ (1\leq i\leq N)$ は数列 $A_{x_i}\ (0\leq x_i\lt i)$ の末尾に整数 $y_i$ を追加することで得られる数列
  • $A_1,A_2,\ldots,A_N$ を辞書順で小さいものから順に並べたときの添字の列を出力してください。
    • ただし、等しい列が複数ある場合には添え字が小さいものが先になるように並べてください。

制約

  • $1\leq N\leq 3\times 10^5$
  • $0\leq x_i\lt i$
  • $1\leq y_i\leq 10^9$
  • 入力は全て整数

解法

Trie木をつくっていく。

     ⓪         ⓪: []
  ↙3  ↘5      ①: [5]         答え
②④     ①     ②: [3]     →  2 4 3 5 1
 ↓2            ③: [3, 2]
③⑤            ④: [3]
                ⑤: [3, 2]

辺の値は、各数列の末尾に付け加える $y_i$ である。
②と④、③と⑤など、実質的に同じ数列は同じノードとする。

たとえば、ノードには以下のような情報を持たせるとよい。

  • children[y]: キーを $y$、値を「自身の末尾に $y$ を加えた数列を表すノード(への参照)」とする辞書
  • indices: そのノードが表す数列が $A_i$ と等しくなるような $i$ の列(昇順)

Trie木を構築後、辺の値が小さい子を優先的にDFSして、訪れたノードの indices を結合していけば答えとなる。

Python3

F - Manhattan Christmas Tree 2

問題文

  • 二次元平面上に $N$ 個のクリスマスツリーがあります。
  • $i$ 番目 $(1\le i\le N)$ のクリスマスツリーは座標 $(X_i,Y_i)$ に存在します。
  • $Q$ 個のクエリが与えられるので、順にクエリを処理してください。各クエリは、以下のいずれかです。
    • タイプ $1$ : 1 i x y の形式で与えられる。$i$ 番目のクリスマスツリーの座標を $(x,y)$ に変更する。
    • タイプ $2$ : 2 L R x y の形式で与えられる。$L,L+1,\ldots,R$ 番目のクリスマスツリーのうち、座標 $(x,y)$ からマンハッタン距離で最も遠いクリスマスツリーまでの距離を出力する。

制約

  • $1\le N,Q\le 2\times 10^5$
  • $-10^9\le X_i,Y_i\le 10^9$
  • $1\le i\le N$
  • $1\le L\le R\le N$
  • $-10^9\le x,y\le 10^9$
  • 入力される値は全て整数

解法

ある座標からのマンハッタン距離が同じ点というのは、ナナメ正方形状に並ぶ。

      3
    323
  32123       ●: クエリ2で与えられる (x,y)
321●123
  32123
    323
      3

今回は $(x,y)$ から最も遠いツリーを知りたい。 4つの辺を分解して、それぞれの方向に最も遠いツリー(が乗っている直線)がわかればよい。
これは $X+Y,X-Y$ の min,max として考えられる。

                各方向別 最も遠いツリー:
  ④↖  ↗①      ①: Xi+Yi が max であるツリー
      ●          ②: Xi+Yi が min であるツリー
  ②↙  ↘③      ③: Xi-Yi が max であるツリー
                  ④: Xi-Yi が min であるツリー

たとえば①の方向に最も遠いツリー $(X_i,Y_i)$ と $(x,y)$ の距離は、$(X_i+Y_i)-(x+y)$ などとして求められるので、 具体的な $i$ の情報は不要で、単に $X_i+Y_i$ の値さえわかれば距離を求められる。(②~④についても同じ感じ)

各方向別に $(x,y)$ と最も遠いツリーとの距離を算出して、その中の最大値がクエリに対する答えとなる。

ただし、一つ気になるのが、たとえ①の方向に最も遠いツリーでも それが $(x,y)$ の右上に存在しない場合は、正しいマンハッタン距離にならない。

        \
          \
      ●    \      ここの点が最大の場合、
              \  ↙上記の式では正しいマンハッタン距離は求まらない。
                ・

しかしこの場合、そのツリーは③方向にも、①方向の距離以上に離れたツリーであり、 ③方向の距離を算出する過程で正しい距離が求まっているので、各方向別の最大値を取れば大丈夫となる。

        \      
          \  /    
      ●    ×      ③(↘)方向だと、①(↗)より距離は大きく算出される。
          /  \    方向別最大値をとれば、誤った①方向の距離が採用されることはない。
        /      ・

※より数学的には、絶対値を max に置き換えるテクニックで導出できる。

よって、$X_i+Y_i$、$X_i-Y_i$ の最大値最小値、計4つの値をセグメント木で管理すれば、 $[L,R)$ の範囲のツリーのみを使うというクエリにも答えられる。

Python3

G - Colorful Christmas Tree

問題文

  • $N$ 頂点の木があります。辺 $i$ は $u_i,v_i$ を結んでいます。
  • 各頂点は最初、赤・青・緑のいずれかの色で点灯しており、$i$ の色は $c_i$ として与えられます。
  • 高橋君は、以下の操作を $N-1$ 回行い、すべての辺を取り除こうと考えています。
    • まだ取り外されていない辺のうち、両端の頂点の点灯色が異なるものを $1$ 本選び、その辺を取り除く。
    • 取り除いた辺の両端の頂点それぞれについて、点灯色を次の規則で変更する。
      • 赤で点灯していた場合、緑で点灯させる。
      • 緑で点灯していた場合、青で点灯させる。
      • 青で点灯していた場合、赤で点灯させる。
  • 高橋君がこの操作を繰り返してすべての辺を取り除くことが可能かどうかを判定し、可能ならばそのような操作方法を $1$ つ出力してください。
  • $T$ 個のテストケースが与えられるので、それぞれについて答えを求めてください。

制約

  • $1\leq T\leq 20000$
  • $2\leq N\leq 2000$
  • $c_i$ は R, G, B のいずれか
  • $1\leq u_i,v_i\leq N$
  • $T,N,u_i,v_i$ は整数
  • $1$ つの入力ファイルに含まれる $N^2$ の総和は $2000^2$ 以下

解法

消せる辺から適当に消すと、(本来は可能なのに)分断された残りが上手く消せなくなることがある。 じゃあってんで、葉から優先的に消そうとしても、消すタイミングによっては親の方を先に操作しないと残ってしまうことがある。

フローで解く。

木は二部グラフとして解釈できる。 各頂点、次数によって「自身が赤の時に何回操作されるか」(同、緑・青)は決まっている。 よって、この3状態を頂点とした $3N$ 頂点で、二部マッチングをおこなえばよい。

DFSなどをおこない、頂点を二部グラフ用に2つに分ける。
適当な頂点(たとえば $1$)から、偶数ステップで辿り着ける頂点群をグループA、奇数をグループBとすると分けられる。

  • $A_{i,c}$($i=1~N,c=\{R,G,B\}$)を「頂点 $i$ が色 $c$ の時に操作する回数」とする。
  • $V_{i,c}$($i=1~N,c=\{R,G,B\}$)を「頂点 $i$ が色 $c$ で点灯している状態」を表す、二部マッチング用グラフの頂点とする。
  • $S,T$ を、二部マッチング用グラフのsource,sinkとする。

このとき、以下のようにグラフを作れる。

  • グループAに属する各頂点 $i$ につき、$c=\{R,G,B\}$ のそれぞれにつき、$S→V_{i,c}$ に容量 $A_{i,c}$ の辺
  • グループBに属する各頂点 $i$ につき、$c=\{R,G,B\}$ のそれぞれにつき、$V_{i,c}→T$ に容量 $A_{i,c}$ の辺
  • 元のグラフで $u→v$ に辺がある場合、$V_{u,c_1}→V_{v,c_2}$($c_1 \neq c_2$)に、容量 $1$ の辺

これで $S→T$ へ最大流を流す。
辺の本数 $N-1$ 流れなかったら、そもそも不可能。
それ以外なら構築可能となる。

元の各辺 $u→v$ に対し、最大流に使われている辺 $V_{u,c_1}→V_{v,c_2}$ の組 $(c_1,c_2)$ が、必ず1つだけ存在する。
この時、頂点 $u$ が色 $c_1$、頂点 $v$ が色 $c_2$ で点灯しているときに、その辺を取り除けばよい。
全ての辺について、その辺を取り除くべきタイミングで取り除けるような操作手順が、必ず構築できる。

各辺につき $(c_1,c_2)$ が必ず一意に決まる略証

全ての辺が、希望のタイミングで取り除ける操作手順が構築できる略証

Python3

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