ABC293

7完。前半ゴツゴツした問題が多くて調子の悪さも感じていたが、後半はかなりいい動きができた。順番に解いていってノンペナ147位はさすがに気持ちいい。

A - Swap Odd and Even

雰囲気的にreverseかなと思い書くとサンプル合わない。隣同士のswapだった。

B - Call the ID Number

愚直にやったときの計算量がどうなるかドキドキしながら読み進めると、一応愚直でいい。ただ、「最後まで番号を一度も呼ばれない人」が0人のケースがないかの確認まではする余裕がなかった。入力を受け取って、シミュレーション(番号iを呼んだらA_iを-1に上書きする)して、A_iが非負のiを(昇順に)vectorに入れて、個数を出力して(これ読んでなかった)、vectorの中身を出力して終わり。けっこう大変。

C - Make Takahashi Happy

DFSしたいけど、頭が破裂しそうなので回避。最大でも18回しか移動しないので、2^18通りの経路(マス目の外に出ちゃうものははじく)を全探索すればよい。座標圧縮すれば計算量が改善されるが、C問題でそこまでやってられんのでunordered_setを使った(個数が少ないことに気づきsetで提出してみたら速くなった)。

解説見たらnext_permutationでいいじゃん草。

D - Tying Rope

グラフと捉えると、木かどうかが重要そう。なもりグラフを考えていたが、「同じ色の端が複数回結ばれることはありません」ということで、次数が3の頂点(今になってみると頂点って何だよって感じだが)はない、どうも連結成分は木でなければループでありそうだ(また、色の情報は使わない)。ということでUnionFind。今回は、UnionFind外のvectorで木かどうかの情報を持った。sameだったらleaderのところをいじって、そうでなければ(あ、ループと何かがつながることはないからmergeするだけでよかったのか)。

解説見て、この設定(木またはループ)だと次数を見ることでも解けるのか(次数1の頂点があるかどうか)。

E - Geometric Progression

まず等比数列の和の公式を導出してみるが、割り算が必要で困る。ということで、行列累乗。要するにA進X桁の111111なので、A倍して1を足すという操作を行列で表せばいい。

ダブリングでできるらしいが、苦手。

F - Zero or One

bが小さいときは愚直で数えられる。テストケースが1000個なのでbが1000くらいまでなら間に合う。bが大きければ?桁数を固定して考えていくと、10^18が1000000(1000進法)と表されるため、bが1000より大きいならば6桁以下であるとわかる(ここ難しかった)。6桁以下なら2^6通りを全探索できる。bを大きくしていって初めてその表現(10110とか)でN以上になる場所を、二分探索で見つける。二分探索では、条件を満たすかが変わる場所の前後を必ず調べるので、二分探索中にぴったりNになったかを判定するだけでいい(bが1000より大きいやつだけカウント)(結果のbは見ない)。オーバーフローしないように、doubleでまず概算する(ほぼ同じコードなのでスコープを切ってコピペ)。

bが1000より大きいときのみカウントするところ、10110(b)が1000より大きいかで判定してて嘘を通したかと思ったが、そもそも二分探索の範囲を1001以上N+1未満(結果のbを見ないため内部でNを探索するよう+1している)としていたのでOKだった。1000より大きいのをはじく方法が2つあって気づかず2つとも実装していて片方が間違っていたけどそれは常に成り立つ条件だったので結果として正しいコードになっていた。

解説なんか難しいな。桁数がO(log(N))になることは気づいていたけど、うーんわからん。

G - Triple Index

C問題と違って座圧は非本質ということでA_iの範囲が小さい。ARC157Cみたいな感じかと思い考えるが、Aの種類数が多いのとクエリの区間が広いのでどうもうまくいかない(平方分割でもうまくいかない)。ここでMoとかいうのを思いつく。なんかしゃくとりっぽいというのを知っていて、この問題はしゃくとりできる。検索窓で探るとMo's algorithmというらしい。出てきたブログ記事を読むと、適用できる条件がもうこの問題そのものみたいに当てはまりすぎていた。ブロックサイズを400に決めて、クエリをソートする。[0, 0)という区間から始める。区間内に何が何個あるかをvectorで持つ(これでしゃくとりできるようになる)。クエリをソートしてしまえば、あとはブロックサイズとか関係なく区間を伸び縮みさせるだけで計算量が落ちている(よくここに気づいた)。ここで、区間を縮ませて区間サイズがマイナスになってしまうのが怖い。が、先に左右へ伸ばしてから縮めればいいと気づいた(よくここに気づいた)。4通りの似た処理を書く。余計なif文が入ってしまったが初めてなので仕方ない(取り除く時間もない)。3次式の差なので2次式になるんだろうなと思いつつすぐにはわからなかったので3次を2回書く。コンテスト中に簡単な問題でMo入門できてありがたい。

(追記)ブロックサイズは400より500のが速かった。binom(K+1, 3)-binom(K, 3)を知りたかったが、パスカルの三角形を考えれば当然binom(K, 2)だった。ある意味「微分」だと思って、どうやったら計算できるのかと思っていたが、二項係数なんだなあ。K^3ではなくK*(K-1)*(K-2)の形のとき楽に「微分」できる。例えばK^2=K*(K-1)+Kだから「微分」して2*K+1になる(3^2に2*3+1を足せば4^2になる)。