Codeforces Global Round 30

A. Sequence Game

min, max の間は全部作れます.min, max の 2 種がある状態をキープするように操作すればよいです.

B. Even Modulo Pair

偶数が $2$ つ以上あればそれが満たします.

偶数が $1$ つあるとき,それとの絡みは $O(N)$ 通りチェックできます.

奇数同士のことだけを考えればよいです.「隣接 $2$ 項」で失敗するなら商は $2$ 以上です.

よって「隣接 $2$ 項」で最後まで失敗した場合,$N$ は $30$ 以下程度で,この場合は全探索できます.

C. Dungeon

$C=0$ のものは後回しにします(先にやる利点が全くありません).

$C>0$ のものは,$B$ について昇順にイベントを行うとしてよいです.$B$ について大・小という討伐順があったときに入れ替えてもよいというタイプの議論をします.

よって $B$ について昇順に処理しますが,討伐可能な $A$ のうち最小のものを使うとしてよいです.これで $C>0$ のものは処理できました.

あとは $C=0$ について,似た貪欲法をもう一回やります.

D. Copy String

$t$ の右の文字から順に,$s$ のどの文字由来であるかを貪欲に決めてしまいます.マッチ可能な文字のうち最も右のものを使っていくとしてよいです.

これで矛盾なく文字の対応を決められたら,文字の移動距離の max が操作最小回数となります.

間の操作手順を埋めるのも,文字が右優先で移動するようにすればよいです.

E. Journey

オイラー路の理論から,”transfer” をいくつか追加することで,奇点をなくすのが目標です.

言い換えれば,奇点同士を transfer で最小重み完全マッチングする問題ということになります.

なお,同じ点を通る transfer が $2$ つあれば結合した方が得なので,偶点を経由して奇点を結ぶパターンなどもありません.

$2$ 点を transfer で結ぶときの最小コストは,「マージ過程の木」を使って表現できます.

辺インデックスが小さい辺から順にマージしていくとき,あるインデックスの辺は,その辺が表すノードの subtree 内における $2$ 点を結ぶ transfer として使えます.

結局,次のようになります:

  • 根付き木がある.各頂点には重み $a_v$ が書いてある.
  • $2$ 点 $u,v$ は,$u,v\in subtree(w)$ のときに重み $a_w$ で transfer できる.

重みを根側から葉側に chmin しておき,深い位置の重みの方が小さいようにしておきます.

$u,v$ は lca の重みで transfer します.

あとは木 dp の要領で,subtree から $2$ 個の点が登場した時点でマッチさせればよいです.

F2. Chain Prefix Rank (Hard Version)

何らかの toposort の数え上げ.ということになります.

まずは条件を満たす toposort をひとつ求めることにします.これは,適当な平衡二分木を持ちながら dfs をして,$v$ を適当なところに挿入するようにすればよいです.$v$ が $l,r$ の間に挿入されるとき,$l\to v\to r$ という辺を張って toposort します.

toposort をして条件を満たす順列 $a$ をひとつ求めておきます.次は数え上げです.

top-down に考えます.ある頂点 $v$ において,根からの $v$ までの値が $x_1,x_2,\ldots,x_k$ となっているときに,子の値は $[x_i,x_{i+1}]$ という区間に分割されます.

$v$ の場所を決めるときに,を含む区間 $[x_i,x_{i+1}]$ の間に $a_v$ を入れたあと,

  • subtree 内で $[x_i,a_v]$ に入るべきもの
  • subtree 内で $[a_v,x_{i+1}]$ に入るべきもの

全体をそれぞれ適当に分割するための多項係数をかけます.この分割は,各グループ内で根側に近い代表元を求めておき,代表元ごとの集合に分割するというようにすればよいです.

はじめに toposort をひとつ求めるために使った $l, r$ が,$v$ がいつ代表元でなくなるかを表しているので,これを数え上げの際に再利用できます.

(私は toposort をひとつ求めて考えましたが,結局これは要らなかったかもしれません.)

G. Pointless Machine

クエリの戻り値は差分をとれば「$p_i$ の近傍のうち $p_1,\ldots,p_{i-1}$ にあるものの個数」とできます.

$2$ 回のクエリを使って $p$ と $\mathrm{reverse}(p)$ を聞けば,各頂点の次数が決定できます.木を特定したいので,「次数 $1$ の頂点をとり,隣接する点を特定し,その辺を削除」というのが反復できれば良いです.

reverse で $1$ 回消費することを考えれば,$30$ 回の質問で次を実現できれば ok です.

  • $v$ が選ばれる.$ans$ が未知.
  • 各質問に対して $ans$ が $v$ の左右どちらにあるかを教えてもらえる.

どのような $v$ でも $ans$ が一意に決定できるように質問を考えます.

$3$ 進法を使います.$n<3^{10}$ なので $10$ 桁それぞれについて $0,1,2$ が決定できれば ok です.

$k$ 桁目について,頂点番号のその桁が $0,1,2$ のどれであるかに注意して $A,B,C$ の $3$ グループに分けて,

  • A, B, C をこの順に結合したもの
  • B, C, A をこの順に結合したもの
  • C, A, B をこの順に結合したもの

をクエリします.これで必ず $ans$ の桁が決定できます.

例えば自分の桁が $0$ であるとします.クエリの結果は $L,R$ で表すことにします.

  • $A$ 内の左にある場合:$LLL$
  • $A$ 内の右にある場合:$RRR$
  • $B$ 内にある場合:$RLR$
  • $C$ 内にある場合:$RLL$

となって全部区別できています.

H. PalindromePalindrome

まだ

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