Codeforces Round 1068

A. Sleeping Through Classes

$s[i]=1$ ならば ANS の $i$ から $i+k$ 番目を true にするという要領です.

制約が小さいので愚直ループでよいです.$i$ を降順にループすれば,s そのものを ANS として使うこともできます.

B. Niko’s Tactical Cards

「$n$ 手目を終えた時点ありうる min, max」が,「$n-1$ 手目を終えた時点でありうる min, max」から決まることが分かります.このことを使って,各時点で可能な min, max を順に計算します.

C. Kanade’s Perfect Multiples

$A$ を unique しておき,昇順に処理していきます.

$B_j$ の $1$ 倍が $A$ に入っていないといけないので,$B$ は $A$ の部分集合です.

$B_i\mid B_j$ のとき $B_j$ を削除できます.このことなどから,次をやればよいです.

  • $A$ について昇順に見る.これまで $B$ に採用した数の倍数であるものはスルーする.そうでなければ $B$ に採用する.ただし,この数の倍数であって $A$ にないものが発見されたら不可能を出力.

具体的な実装として,$B$ に値を採用しながら,各 $A_i$ が $B_j$ の倍数になったかどうかを管理します.この際,採用した値の倍数についてループします.

計算量はどうなるでしょうか?おおよそ「採用した値の倍数が $A$ に含まれるかどうかを調べて,true が返ってくる回数」に比例します.これは $A$ の約数の個数の総和です.これを上界として見積もれば,まあ間に合うだろうということになります.

実際には,$x\mid y$ のとき $A$ の約数として $x,y$ 両方が登場するということも起こらないので,「高度合成数の約数の個数」のような上界に比べてかなり小さいケースしか作れないはずです.

D. Taiga’s Carry Chains

「繰り上がり回数」というのは,「popcnt が減少する回数」と考えます.

結局,$n$ に $2^l$ を $k$ 回加算して,popcnt を最小にできればよいことになります.

$k>30$ ならば,popcnt を $1$ にできます.lowbit への加算を繰り返せばよいです.

$k\leq 30$ について解けばよく,適当な桁 dp で解けます.

E. Shiro’s Mirror Duel

  • $0$ および $n-1$ を正しい位置に運ぶ.
  • $[1,n-1)$ 部分について解く.

ということをやります.

まず $0$ を正しい位置に運ぶのは単に当たり待ちをすれば期待値 $2$ 回でできます.

そのあと $n-1$ の当たり待ちの仮定で $0$ が悪い状態になってしまうことがあるのですが,このような失敗が発生したとき $0$ と $n-1$ の位置が左右対称で,次の行動で必ず $0$ または $n-1$ が正しい位置に来ます.このことを考慮すると,一度 $0$ が正しい位置に来た状態から $0, n-1$ の位置を合わせるところは期待値 $3$ 回でできることが分かります.

期待値 $5$ 回で $n$ を $2$ 小さくできる,というような解法になっていて,目標クエリ回数を達成できます.

F. Isla’s Memory Thresholds

$a$ が単調減少であることから,リセットまでに進む距離は単調増加します.

距離の種類数は $O(\sqrt{N})$ なので,距離が定数であるようなところをまとめてシミュレーションする形にすれば,クエリあたり $O(\sqrt{N}\log N)$ 時間になります.おおよそ次の $2$ ステップからなる計算になると思います.

1. 次に進む距離 $d$ を求める.(二分探索)

2. 距離 $d$ 進む回数を求める.(二分探索)

私の解法はおおよそこれの定数倍高速化です.$O(\sqrt{N\log N})$ にはできるつもりだったのですが細部の解析をさぼったし,結局提出されたものはそのオーダーのままのはず.ただしそのまま少し調整すれば方針で $O(\sqrt{N\log N})$ にはなることが提出後に分かったのでそれを解説します.

発想としては,二分探索類を線形探索や指数探索に置き換えます.もっと雑にやるなら,こういうのは全部指数探索にしてしまうとオーダーレベルで損することはないし,実は勝手にオーダーが良くなっているということもときどきあります.今回がそうだったということですね.

指数探索は,おおよそ次のようなアルゴリズムです.

ok = 1, ng = 2;
while (check(ng)) ok += ok, ng += ng;
while (ok + 1 < ng) いつもの

計算量が $O(\log ans)$ になる(特に $O(ans)$ になる)ことが特徴です.$ans$ が小さい場合には $O(\log n)$ より良いです.

1, 2 をともに指数探索にした場合の計算量オーダーを考えます.

1 について,$d\leq \sqrt{n\log n}$ であるような $d$ を全部発見するのにかかる時間は $O(\sqrt{n\log n})$ です.ここは線形探索($d$ を $d+1$ に置き換えられるかのチェックをしながらインクリメント)にしても同じ計算量になります.これは,発見するのにかかる時間と $d$ の増分が比例するためです.

$d\geq \sqrt{n\log n}$ であるような $d$ を全部発見するのにかかる時間はどうでしょう.種類数が $O(\sqrt{n/\log n})$ でこれを毎回二分探索で発見すると,$O(\sqrt{n\log n})$ 時間です.1 が $O(\sqrt{n\log n})$ であることが確かめられました.

2 について,$d\leq \sqrt{n/\log n}$ であるような $d$ に対しては $d$ ごとに $O(\log n)$ 時間と評価します.合計 $O(\sqrt{n\log n})$ 時間です.

$d\geq \sqrt{n/\log n}$ であるような $d$ については,そのような $d$ に対する $ans$ の総和が $O(\sqrt{n\log n})$ です.よってここは線形探索でも(したがって指数探索でも)$O(\sqrt{n\log n})$ 時間です.

  • ttps://codeforces.com/contest/2173/submission/352058554

実装ミスっててワーストケース $O(N)$ の類になっていて Hack されたので直した.

やったら速くなったが,ちゃんとこの解法に対する最悪ケースを作ればそうでもなくなると思うがどうだろう.

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