ABC283

ABCDFGの6完。

A - Power

9^9でGoogle検索してしまったが、自明に10^9より小さかった。powを使った。intに収まる範囲なら誤差は出ない(それが保証されるのは四則演算くらいだった気もするので提出してから0.5足したほうがよかったかなとか少し心配したけどまあこれでWAになったらそのほうが嬉しい(powで誤差が出る例が手に入る))。

B - First Query Problem

E問題とか用のテンプレを書くだけ。素早く書けた。

C - Cash Register

注意すべきは表示が0のときに"00"を押しても変わらないということくらいかな(解説放送聞いてて思い出したけどS=0のケースがないことも確認した)。どうやったら証明したことになるのかわからず不安なまま実装して不安なまま提出した。

D - Scope

問題文をどう理解したか書けないな。とにかく、対応する括弧まで巻き戻せればいい。左から見ていって各文字の個数を保存しておく。開き括弧の位置をスタックで管理。閉じ括弧で対応する開き括弧のときの個数に戻す。英小文字を追加するときに追加済みか判定。

サンプルに2回も助けられた。実質2ペナ。最初、括弧を閉じたタイミングで判定していたが、そのとき個数を戻すのを忘れていた。対応する括弧に入る前の文字をカウントしていなかった。

(追記)個数を管理する必要があると思っていたけど存在するかだけでいい。文字も26種類しかないのでintにビットで詰め込める。また、スタックに入れるのは位置ではなく対応する括弧当時の文字集合でよかった。だいぶシンプルなコードになる。

E - Don't Isolate Elements

対称性から1行目は操作しなくてよくて2行目から必要なら操作して最後に全体を反転して最小値をとる(操作回数がH/2を超えることはないので)みたいのを考えていて、雑に実装していった。しかし、自由度があるときがかなり厄介であることがだんだん明らかになってくる。隣の行と操作回数を同じにするかどうかをH-1個決めればいいのだが、これはもうフローとか2-SATが必要そうな感じだし使っても無理そうなのでやばい。そういうときはDPが解法なんだよな。実際、どっちに合わせるかを4通りくらい持てばDPできそうな気もする。しかし相当難しそうなので一旦飛ばした。

(追記)あまりに難しいのでツイートや解説にできるだけ頼りながら。DPテーブル自体は小さい。2*2要素をH回更新する。2個前で操作したか、1個前で操作したか、現在の位置で操作するかの8通りを試し、1個前の行に孤立した要素がなければ遷移する(最後の行に注意)。番兵使いまくり。もうね、さっさとACして逃げたい以上の感情がなかった(この「以上」が我ながら変わった用法だなと思っていたが「悔やむと書いてミライ」の歌詞だった)。

F - Permutation Distance

難しそうな見た目だが、要するにできるだけ場所も数値も近いものを探せと。視点を固定すると、山を足せば(引けば)よさそう。相手を自分より左にある自分より大きいものに限れば、斜め線(山の片側)を足したものを左から見ればいいのでかなり簡単そう。と思ったけど自分より大きいのだけ見る必要があるので、視点を動かしていくことを考えるとセグ木とかが要りそうだ。やはり0-indexedに直す必要がある。最小値のセグ木を2本持ち、P_i の位置に P_i - i を置いていく。この最小値を求めれば、(左から順に自分より左で大きいものを対象にしているとき)離れたものほど都合が悪くなっている。実際の値を知るには、その時点でのiを足せばいい。自分より右の相手については、順列と最小値のvectorをreverseして同じことをやればいい。最大値のセグ木も要ることに途中で気づいたけど面倒だったので符号反転で対応したがなかなかサンプル合わず、2本のセグ木のうち符号反転するのがどっちかを間違えていた。

(追記)解説を見て、たしかにPの大小を反転させれば(reverseするのとあわせて)「左の大きいもの」を見るコードだけを書けばよくなる。なんで気づかなかったんだ。

G - Partial Xor Enumeration

見た目がかなりやばいけど、よく読めばそうでもない。列というより多重集合。LRの大きさは、どうあがいても0以上2^60未満の整数しか作れないので2^60以下とわかる。となるともう基底を作ればよさそうだ。基底を大きい順に見てできるだけ削っておく(それを使ったとき、それを使う最小の数から始めるため)。あとは(0-indexedにしたうえで)LからRまでの数を変換しながら出力するだけ。