Codeforces Round 1044

A. Redstone?

列 $a$ の場合の左端と右端の比は $\frac{a_2}{a_1}\cdot \frac{a_3}{a_2}\cdots \frac{a_{n}}{a_{n-1}}=\frac{a_n}{a_1}$ となるので両端に同じ値を置けるかどうかを判定すればよいです.

B. Villagers

$a>b$ であるような $2$ 数に操作をすると $a-b,0$ となりますが,これら $2$ 数は連結になって連結性だけが問題なので,$0,0$ になると思ってもよいです.

結局,$2$ 数を選んで大きい方の値をコストとしてそれを $0$ に変える,という操作になります.$\max$ が選ばれる操作について考えると,最上位 $2$ 個に対する操作をやってしまってよいことが示せます.結局ソートして上位から $2$ 個ずつ組にしていくような方法を計算すればよいです.

C. The Nether

まず $S$ を頂点全体として,$(x,S)$ の形のクエリ $n$ 回を質問します.これで各 $x$ を始点とする最長パスが求まります.これを $a_x$ としましょう.

$a_x$ が最大であるような頂点をひとつ選んで,そこからパスを作っていきます.各時点で,「最長パスの次の頂点」を見つけられれば良いです.$x\to y$ 辺を探すときには,$a_y=a_x-1$ となる $y$ を候補として全探索し,$S=\{x,y\}$ の形のクエリを使えばよいです.このタイプのクエリでは同じ $y$ は一度しか選ばれないため,全体のクエリ回数は $2n$ 以下(より詳しくは $2n-1$ 回以下)になります.

D. Chicken Jockey

結構難しいと思いました.

落下ダメージを与えるところを固定すると,だいたい右から落下ダメージが入るようにする操作順になる(インデックスに等しい落下ダメージを入れられる)ということだと思ったのですが,単に落下ダメージの有無という見方だけだと上手くいかなかったのでそれを細分化しました.

要素を落下ダメージで $0$, $1$, $2$ に分類します.$2$ は $2$ 以上の落下ダメージが入る場合です.これで $0$, $1$, $2$ からなる列を作ると,$2$ の直前は $0$ でなければならないことが分かります.

先頭が $0$ ではない,$2$ が来る場所はインデックス $2$ 以上のところ.などの自明な必要条件もあります.

これを満たす列をとってくると,その列以上の落下ダメージを実現する操作列があります.$0$ が予定されているものを右から順に破壊して,破壊したらそのまま右方向に破壊していけばよいです.この手順では,「$2$」に分類されているものはインデックスと同じだけの理論最大落下ダメージを実現できていることも分かります.

あとはこの $0, 1, 2$ からなる列を順に定めていくことを考えて dp で答えを計算できます.

E. I Yearned For The Mines

方針として,

  • 集合 $S$ を選ぶ.ただし $G-S$ の連結成分がパスばかりになるようにする.
  • $x\in S$ に対して,「1 x」「2 x」という操作をする.
  • 残った連結成分がすべてパスになっているとき,各パスを端から順に操作 1 していく.

とします.このような $S$ を $|S|\leq n/4$ でとれればよいです.

これは木 dp で最適化できると思いますが,次のような貪欲でも十分です:葉側から順に見たときに,subtree size がはじめて $4$ 以上になっている点を $S$ に追加し,subtree を削除する.

このように $S$ をとったとき $G-S$ の連結成分はすべて頂点数 $3$ 以下,しがたってパスなのでよいです.

F. Flint and Steel

包含関係にある $2$ つの区間は両方使うことがないとしてよいです(あるとしたら短い方が先ということになり,これを単にキャンセルした方が得).なので区間には単調性があって,さらにソートして隣接する区間同士は「隙間ができない」「両方が相手の区間の中点を覆うことはない」という必要条件があります.

これは十分条件にもなって,必要条件のもとで隣接する区間の操作順序が適切になるような操作順をとれば全体でも条件を満たします.

$\dp[i]$ を,$i$ 番目の区間を最小で何番目に使えるかを表す dp テーブルとしてこれを計算することを目指します.

これは最短路問題になっているので,BFS によって $\dp[]$ について昇順に計算していくことができます.BFS はすべての辺を陽に持たなくても,「ある頂点から $1$ 手で行ける頂点のうち未訪問の点」が列挙できればよいです.今回だと,$i$ からの行先は

  • $i-e[i]<j-e[j]<i+e[i]\leq j$
  • $i\leq j-e[j]<i+e[i]<j+e[j]$

などで,これは区間クエリの形で検索できます(例えば前者は 「$j-e[j]$ がこの範囲にあるような $j$ の最大値」の取得に帰着).これらを検索する用のセグメント木を持って,一度訪問した点はデータ構造から削除するようにすればよいです.

最短路といっても添字順に DAG なので,添字順に dp[] を求めていくこともできて,公式の Editorial はその方針です.$2$ 次元データ構造の $\log^2$ を回避しようとすると,少し挿入や求値のタイミングに気を配る必要があります.

CodeForces
スポンサーリンク
シェアする
maspyをフォローする
maspyのHP
タイトルとURLをコピーしました