Loading [MathJax]/jax/output/CommonHTML/jax.js

AtCoder Beginner Contest 401 E,F,G問題メモ

E - Reachable Set

問題文

  • N 頂点 M 辺からなる無向グラフがあります。

頂点には 1,2,,N の番号がついており、i 番目 (1iM) の辺は頂点 ui と頂点 vi を結んでいます。

  • k=1,2,,N について、次の問題を解いてください。
    • 次の操作について考える。
      • 頂点を一つ選ぶ。選んだ頂点と、選んだ頂点に接続する全ての辺をグラフから削除する。
    • 上の操作を繰り返すことで、次の条件を満たすことができるか判定せよ。
      • 頂点 1 から辺をたどって到達できる頂点の集合が、頂点 1, 頂点 2,, 頂点 k のちょうど k 個からなる。
    • 可能な場合、条件を満たすために少なくとも何回操作を行う必要があるか求めよ。

制約

  • 1N2×105
  • 0M3×105
  • 1ui<viN (1iM)
  • (ui,vi)(uj,vj) (1i<jM)
  • 入力はすべて整数

解法

可能かどうかの判定は、以下になる。

  • 「両端がどちらも k 以下の頂点を結ぶ辺」だけで、1k が連結になるか?

可能な場合、消さなければいけない頂点は、以下になる。

  • 1k のいずれかと辺で接している、k+1 以上の頂点

k=1,2,...,N の順に答えを求めていく。以下のデータを用意する。

  • Lsmall[i]:=i と辺で結ばれている i1 以下の頂点の集合
  • Llarge[i]:=i と辺で結ばれている i+1 以上の頂点の集合
  • UF:= Union-Find木
  • S:= 今現在、1k のいずれかと辺で接している、k+1 以上の頂点の集合

最初、UF は全頂点バラバラ、S は空とする。
k=i の時、以下のように状態を更新すればよい。

  • Lsmall[i] の各頂点と iUF 上で結ぶ
  • SLlarge[i] の要素を追加し、i 自身が入っていたら除く
  • UF1k が非連結なら(頂点 1の属する連結成分のサイズが k 未満なら)不可能
  • 連結なら、|S| が答え

Python3

F - Add One Edge 3

問題文

  • N1 頂点の木 1 と、N2 頂点の木 2 が与えられます。
  • 1 の頂点 i と、木 2 の頂点 j を双方向に結ぶ辺を追加すると一つの木が得られます。この木の直径を f(i,j) と定めます。
  • N1i=1N2j=1f(i,j) を求めてください。

制約

  • 1N1,N22×105
  • 1u1,i,v1,iN1
  • 1u2,i,v2,iN2
  • 入力されるグラフは共に木
  • 入力される数値は全て整数

解法

それぞれの木につき、以下を計算する。これは、Rerooting(全方位木)で求められる。

  • Farthestt[i]:=t の中で、頂点 i から最も遠い頂点までの距離

また、2つの木の(結ぶ前での)直径のうち、大きい方を D とすると、以下が成り立つ。

  • g(i,j):=Farthest1[i]+Farthest2[j]+1 として、
  • f(i,j)=max(D,g(i,j))

1 側の頂点 i を固定する。

この時 f(i,j)D になるか g(i,j) になるかは、 Farthest2[j]DFarthest1[i]1 かどうかで判定できる。

Farthest2 をソートしておけば、二分探索で D になる方の個数が求められる。

またソート後の累積和も計算しておけば、 g(i,j) になる方だけの Farthest2[j] の総和もわかるので、答えが計算できる。

Python3


基本的な解法は変わらないが、全方位木など使わなくても、もう少し単純に以下のように考えることもできる。

  • 木において、各頂点から最も遠い頂点の1つは、木の直径の両端のいずれかになる。

木の直径の両端の頂点 u,v を求め、u,v から各点までの距離 du(i),dv(i) を求めれば、Farthest[i]=max(du(i),dv(i)) で求められる。

G - Push Simultaneously

問題文

  • 平面上に N 人の高橋くんと N 個のボタンがあります。
  • 平面上には原点があり、原点から東に x メートル進み、北に y メートル進んだ位置を座標 (x,y) で表すこととします。
    • i 番目 (1iN) の高橋くんははじめ座標 (sxi,syi) にいます。
    • i 番目 (1iN) のボタンは座標 (gxi,gyi) にあります。
  • 高橋くんたちはそれぞれ移動をした後、この N 個のボタンを一斉に押したいです。
    • 各ボタンは、そのボタンがある座標にいる高橋くんだけが押すことができます。
  • それぞれの高橋くんは秒速 1 メートル以下の速さで好きな方向に進むことができます。
  • 高橋くんたちが目標を達成するために必要な時間を求めてください。
    • 相対誤差が 106 以下の時、正解と判定されます。

制約

  • 1N300
  • 0sxi1018 (1iN)
  • 0syi1018 (1iN)
  • 0gxi1018 (1iN)
  • 0gyi1018 (1iN)
  • (sxi,syi)(sxj,syj) (1i<jN)
  • (gxi,gyi)(gxj,gyj) (1i<jN)
  • (sxi,syi)(gxj,gyj) (1iN,1jN)
  • 入力はすべて整数

解法

要は、N 組の高橋君とボタンをマッチングさせた時、最もユークリッド距離が大きい組の距離を最小化させる問題。

実数 X に対して以下の問題が解ければ、答えを二分探索できる。

  • 高橋君 i とボタン j のユークリッド距離を d(i,j) とする。
  • 高橋君とボタンをそれぞれ表現する 2N 個の頂点からなる二部グラフを考える。
  • d(i,j)X であるような i,j のみに辺があるグラフに、完全マッチングが存在するか?

これは愚直に各辺を調べた後に最大流問題で O(V2+VE) などで解ける。(V 頂点数、E 辺数)

答えとしてあり得る最大値を M とすると、M2×1018<261 程度になるので、 二分探索で答えを求めるには、上記に約60の定数倍がかかる。

高速な言語ならこれで間に合う。

ただし、あまり各 d(i,j) と比べて大きすぎる値を M としてしまうと、全ての辺が条件を満たし E=V2 となる。
これが繰り返されると、最大流の計算で毎回 O(V2.5) の計算量がかかってしまう。
言語によっては時間が厳しい。

大雑把に答えの下限と上限を見積もってから二分探索をすることで間に合った。
(ただしこれはテストケースに助けられているだけであり、299組が互いに近く、1組だけ集団から離れた高橋君とボタンとかがあるとあまり高速化になってない)

  • 下限: iminjd(i,j)(各 i に対し、最も近い j への距離の和)
  • 上限: imaxjd(i,j)(各 i に対し、最も遠い j への距離の和)

公式Editorial では、そもそも答えの候補は N2 個しか無いのだから、それ基準で二分探索すると繰返し回数は O(logN) で済むよ、と言っている。確かに。これなら繰り返しは20回未満で済む。

Python3

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