ARC151

3完。これもARC。

A - Equal Hamming Distances

ハミング距離が何だか忘れたので説明を開いて読む。こんな単純な概念でもあたりが付いてないものを形式的に書かれると(短時間で読むのは)しんどいな。自分の理解が正しいか一応ググっても確認した。

SとTで対応する文字が違うとき、どちらに合わせるかでハミング距離に1だけ差が付く。よって文字が違う場所が偶数個でないときは-1。偶数個なら半分をSに半分をTに合わせればいい。対応する文字が同じときは影響ないので全部'0'にする。あとは先頭からヤバくなるまで'0'を配置していくのだが、ここの実装がけっこう難しい(半分が'0'というわけでもない)。ハミング距離の差を管理しておき、基本的に'0'を置き、文字が違う場所の残り個数とハミング距離の差の絶対値が等しいとき距離が大きいほうへ合わせる。ギリギリの状況になるまでは何もせず、ギリギリになったら対策するというのが最適。

B - A < AP

並べ替えて辞書順で大きくなるものを数える。しばらく考えて、i文字目まで同じでi+1文字目で初めて大きくなるものの個数をi毎に数える方針で行こうと思った。そのためにはまず、長さKの数列(T_1, ..., T_K)で、T_1がT_2より大きいものの個数を返す関数を書く。大体半分。等しい場合がカギで、その2個が等しい通り数(これは簡単)を引いてから半分にすればよい。で、話を戻すと、先頭のいくつかが変換後も等しいという情報からだんだんKが減っていく。雑に書いてみるとサンプルが合わない。考え直すと、P_i=iのときもよくわかってなかったし、等しい関係でループができることを考えてなかった。なるほどUnionFindが必要なのか。ループしたら等しい情報が増えないこともある(自己ループで自明だったけど)。最後の1個だけが異なるということはないんだけど、今考えると最後は必ずループになるということかな(当時は解釈ができなくてもやもやしたまま提出した)。

C - 01 Game

合法手によって同じ性質を持ったゲームに分割される(あるいは最初から分割してある)ということで、いかにもGrundy数という見た目。さすがにARCでそんなの出さんやろと思ったけど、他に思いつかないし手でやるのもめちゃくちゃ時間がかかるので愚直でGrundy数を書いた。実装上、書き込む数は1か2にする(何も書いてないのを0で表す)。めっちゃ深いfor文を書いてきれいな結果が出てくる(意外と実行時間が短い)。規則性をコードに落とし一致するか確認するコードにして一致したのでそれを使って問題を解く。X_iとNで終わる区間Grundy数を求めてxorとってくだけ。

愚直書いて規則性見つけるしかしてないのに時間かかった(どこで楽しめばいい?)。そもそもB問題が難しくてかなり時間を食われている。

D - Binary Representations and Queries

超立方体の半分を選択して対角線で反対側に足すのだと誤読。実際は辺を辿って近くの選ばれてない側に足すのだった。これに気づいたのが終了2分前なのが悲しい。状況の理解を深めるために愚直を実装していて全然サンプルが合わず気づいた。操作の種類数が少ないと思ったけど結局2^N通りくらいに分かれるし、操作の順序も(少なくとも同じX_i同士は)入れ替えられない。高速ゼータ変換みたいなものだとしても深すぎて計算量的にとても間に合わない。

(追記)誤読が痛かったね(何もわからないままネタバレを見てしまったという意味で)。累積和みたいな操作になるのでX_iが違えば入れ替えていいらしい(よくわかってない)。そうなると簡単で、0側と1側の寄与をクエリを受け取りながら計算しておけばそれを使ってN回更新するだけ。