ARC138

3完。面白かった。先週のABCの反省を生かし、夕方に緑diffを1問やって、ぷよ観戦も早めに切り上げた(ARCを楽しむ心の状態にするため)。これだけ上手く行って結果は出ないの草。

A - Larger Score

ちょっとでも大きくなればいい。目標を達成するには、境界において(スコアが大きくなるような)スワップが1回は行われる必要がある。そのスワップ対象の要素が元々どこにあったかを固定して考えると、操作回数はその要素間の距離になる(それぞれ境界まで持ってくれば達成できるし、それより少ない回数では両方を境界まで持ってこられない)。全探索は意地でも通さないという制約なので、もう少し考える。境界の右側の候補を考えると、境界からより遠くてより小さい要素は使う意味がない。左側も同様で、より遠くてより大きい要素は使う意味がない。左側は、境界から見て最小値で塗りつぶす感じにしておく。そうして左側を左から見て、右側はしゃくとりをすればよい。左側で塗りつぶされた(変更された)要素はどうせより優れた要素があるので答えの最小値を求めることに影響しない。しゃくとりは、だんだん右側で大きい要素が要求されるようになるので、見つかるまで進めていい。端まで来てもないならそこで探索は終わり。

B - 01 Generation

操作によって先頭が1になることはないので、先頭は0である必要がある。全部0は作れて、そうでないとき先頭は01である必要がある。あとはまあ末尾に0を入れるタイミングでわりと何でも作れそうな気がしてしまうが、しっかり考える。01111101みたいのが作れるか考えると、これは不可能(直前の操作はAであり、戻すと0000010でこれは先頭が1の文字列からしか生成されない)。操作Aをするたびに何が起こるかを観察すると、1要素ずつ隣と違う数になる痕が1つ増えてその後減ることがない。一方、末尾に0を好きなだけ追加して好きな列を作るパートは、操作Aの回数だけしかできない。つまり、操作Aの回数を最大に見積もって、それより右の要素を同じ数毎にまとめた区間数がそれよりも多かったら無理、そうでなかったらできる。実装したらサンプル1で落ちる(笑)。最後に操作Bを好きなだけできるの忘れてた。末尾が0なら区間数を1少なく数える。かなり負荷の高い問題で証明はあきらめたが、なんとかAC。

解説はなんか天才っぽいなー。

C - Rotate and Play Game

まずシフトしないバージョンを考える。最小太郎君に小さいものを取らせることを考える。最小太郎君の1個目は最初の2個のどっちか、2個目は1個目より後で4個目までのどれでも取らせることができる。まあ普通に実装するなら左から見て優先度付きキューを使うだろう。2個目を1個目より右から取る必要もなくて、しれっと左から取って1個目がこれでしたと言えばいい。で、シフトする場合だが、円を描いて、小さいものが多い場所から始めたい。不正をした場合でもスコアの自明な上界として最小太郎君が小さいほうから半分を取った場合のスコアがある。半分の要素を拾えればいいのでこの上界は達成できそうだ。完全に均等な配置ならそれでいいし、不都合に空きがあれば逆に連続してたくさんある場所もあるのでそこから始めればいい。どんな配置でもできそうなのに、具体的にどうしたらいいかわからなかった。しばらくして累積和を思いつく。小さい半分の要素に印を付け(境界で等しい要素が複数あればどれを選んでもいいので全体からちょうどN/2個を選ぶ)、印があるところは1、ないところは-1にして新たな数列を作り累積和をとる。これは1周して0に戻ってくるが、途中で負になると最大スコアが達成できない。そこで累積和の最小値の場所から始めれば負にならないというわけ。これで気持ちよく解けている。

D - Differ by K bits

K=1ならグレイコード。Kが偶数ならpopcountの偶奇が変化しないので不可能。Nが1より大きくN=Kなら2種類しか作れないので不可能。グレイコードをいじるか、正面から分割統治に行くか、迷うところ。K=N-1のケースもよくわからないし、結局どちらの方針もいい感触は得られなかった。できそうではあるけどふわふわしていて接続できない感じで進まない。