Codeforces Round 707 (based on Moscow Open Olympiad in Informatics)

A. Going Home

$a_i+a_j$ ($i<j$)を計算することを何度も繰り返せば,鳩の巣原理より $2\cdot \max(a)+k$ 回程度の探索回数で,$k$ 組程度 $a_x+a_y=a_z+a_w$ が得られます.ただし $(x,y),(z,w)$ に共通要素がある場合が回避できていません.

$(i,j)$ を $j$ について昇順に列挙していき,$(x,y),(i,j)$ のタイプで共通要素があったとします.このとき,$a_p=a_q$ の関係がひとつ見つかります.これを失敗と呼ぶことにします.

同じ $(p,q)$ に対応する失敗は高々 $N$ 回です.$2N+1$ 回失敗すれば,相異なる $(p,q)$ は $3$ 組以上得られます.$a_p=a_q$ となる $(p,q)$ が $3$ 組あれば,それらの関係者から $a_x+a_y=a_z+a_w$ となる $(x,y,z,w)$ を見つけることができます.

よって,$j$ を昇順に単純な探索を行えば,高々 $O(N+\max a)$ 回の探索で解が見つかる,または最後まで全探索を終えることができます.

B. Two chandeliers

時刻 $[0,t)$ での一致回数を数えることができれば,不一致回数が数えられ,二分探索で答が求まります.

$a_i$ や $b_j$ が distinct という制約から,一致する $(i,j)$ の候補は $O(n+m)$ 通りです.これを全探索します.$(i,j)$ を決めると,一致時刻の条件は CRT で $\mod \mathrm{LCM}(n,m)$ ていくつという形で書けます.よって数え上げも簡単です.

C. Matrix Sorting

操作を逆順に考えます.

はじめ,「$i$ 行目よりも $i+1$ 行目が後ろにある」という制約が $H-1$ 個ある状態からはじめます.

ある列を $x_1, \ldots, x_H$ とするとき,その列に関する操作(ソート前の状態に遡る)ができるのは,制約がある $i$ すべてについて $x_i\leq x_{i+1}$ となっている場合です.この列について操作すると,$x_i<x_{i+1}$ になっている部分に関する制約を忘れることができます.

操作は貪欲に可能な限り行ってよいことも分かるので,これをシミュレーションすればよいです.

D. Tiles for Bathroom

各 $(i,j)$ について,その点を左上隅とする正方形に関する計算を行います.

計算結果として,色の種類数が $1, 2, \ldots, 10$ になるときの正方形の大きさと,そのときの色集合がとれるようにします.これを $\mathrm{dp}[i][j]$ とします.

$(i,j)$ を左上隅とする $k\times k$ の正方形は,$(i+1,j)$, $(i,j+1)$, $(i+1,j+1)$ を左上隅とする $(k-1)\times (k-1)$ の正方形の和なので,$\mathrm{dp}[i][j]$ は $\mathrm{dp}[i+1][j], \mathrm{dp}[i][j+1], \mathrm{dp}[i+1][j+1]$ から求まることが分かります.

E. Subset Trick

  • $L_k$ を大きい方から $k$ 個の和
  • $R_k$ を小さい方から $k+1$ 個の和

として,$L_k<R_k$ なら $R_k-L_k$ のスコアが発生.というタイプの計算に帰着できます.

ここで,$f(k)=R_k-L_k$ は下に凸です.$k$ をインクリメントさせたときの $R_k$ の増分は増えていき,$L_k$ の増分は減っていく($-L_k$ の増分が増えていく)からです.よって,$f(k)>0$ となる $k$ の範囲は適当な凸探索で求まります.

$f(k)$ やその区間和の計算が $O(N\log N)$ 回行えればよい,ということになります.これは値方向をインデックスとするセグメント木で行えます(私は平衡二分木を使ってかなり冗長な実装をしてしまいましたが).

F. Cupboards Jumps

次のような dp 解法を考えます:

  • $w_{i-1}$ まで考慮した時点で,$\lvert h_{i}-h_{i+1}\rvert$ として可能な整数全体の集合を $\mathrm{dp}[i]$ とする.

$w=w_i$ として,$S=\mathrm{dp}[i]$ とするとき,$S’=\mathrm{dp}[i+1]$ を得るには次のようにすればよいです.

  • $S$ を $[0,w]$ に制限する($w+1$ 以上の要素をすべて破棄する).
  • $w\in S$ ならば $S’=[0,w]$ とする.
  • $S=\emptyset$ ならば $S’=\emptyset$ である(この場合即時 NO を返してよい).
  • そうでないとき,$S’=\lbrace w-x\mid x\in S\rbrace \cup \lbrace w\rbrace$ である.

$S$ を区間の和集合として管理することで,まず $O(N^2)$ 時間での解法があります.これを高速化します.$S=[l_1,r_1]\cup [l_2,r_2]\cup\cdots$ として,$r_i\leq l_{i+1}$ を満たすような列として扱うことにします.

すると,全体 reverse や全体に対する遅延作用に加え,列の先頭や末尾に対する操作ができれば十分ということになるので,deque のようなデータ構造を使えば全体で $O(N)$ 時間になります.std::deque では reverse が $O(1)$ 時間ではないはずなので,そこは自作しました.

最後に,判定だけでなく復元があることが厄介です.ただし,ある区間は挿入されてから削除されるまで,常に $x\to w-x$ の規則で遷移可能だということになります.よって各区間について,生成されるタイミング,その区間に遷移可能な親区間および座標を持つようにすれば復元できます.

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