ARC154

4完。ARCで橙パフォは初めて。Highestも更新。幸せすぎて怖いという感覚。

橙パフォが取れた原因は、ABが簡単で差が付かなかったこと、Cが自分にとって簡単に感じる問題だったこと、Dの実装が奇跡的に一発で通ったこと、EFが難しかったこと。当たり前だけどめちゃくちゃ運がいい。

A - Swap Digit

操作によってAとBの和は変化しない。偏らせればよさそう。やや不安だったので、AとBの平均をS、AとSの差(の絶対値)をDとして、A*B=(S+D)*(S-D)=S^2-D^2でDが大きいほど積は小さくなるねと一応確認。Aが小さくなるようにswapして、AとBそれぞれ998244353で割ったあまりを求めて掛ければいい。

B - New Place

最初に、ソートして一致するかを確認する(一致すれば可能だしそうでなければ不可能)。以下、可能なときを考える。Tが1234567(英字はわかりにくいので数字で考えていた)みたいのだと仮定すると、i < j かつ S[i] > S[j] となる最大の i までは操作する必要があるし、そこまで操作すればTと一致させることができる。同じ文字が複数入っているときが厄介。同様の考え方を適用しようとすると、SとTを後ろから見ていって、Sの文字をTの文字に貪欲に対応させていくという感じになる。対応しなかったSの前半を操作して好きな位置に入れればTに一致させることができる。

雰囲気合ってそうなので未証明で実装してAC(いかにもARCという感じ)。あとから解説を見ると、なんで自分はこのように明快に考えることができなかったのかと思う。まあそれが実力ってことだ(身も蓋もないが)。

C - Roller

例えばBが順列のときを考えると、1回でも操作したら一致させることはできない。ただし、最初から一致していて操作が必要ないこともあるので、まずAとBが一致しているときはYesを返し、そうでないときBで連続する同じ数が存在しなければNo(ループしてることに注意)。これで、Bに同じ数が2つ連続する部分がある場合だけ考えればよくなった。2連続で同じ数があればその余裕を使って好きなだけrotateできる。同じ数が続く長さも自由に変えられる(長さ0にすることもできる)。AとBにそれぞれstd::uniqueをかけて、先頭と末尾が同じ数なら末尾を削除する。2乗が許される制約なので、rotateさせながらしゃくとりでBがAの部分列になっているか見ていく(B問題と似たような処理)。

D - A + B > C ?

まず、2000の階乗と2^25000を比較する。(対数をとると)1.31倍ほどしか違わない。情報をほとんど無駄にできない、かなりきつい制約だ。解ける気がしない。

「P はプログラムとジャッジの対話の開始前に決定される。」という制約が目に付く。少し前のABCでインタラクティブな問題が出たときは、どうもAdaptiveであるようだったが、今回は違うということだ。例えば乱択により答えがNoとなる質問を見つけることができる。また、質問の(i, j, k)は相異なる必要がないことに気づく(実際サンプルでもそういう質問をしている)。例えばiとkが同じなら答えは常にYesなので、同じ数があって意味のある質問となるはiとjが同じときのみ。そういう質問だけで解けるんじゃないかと当たりを付け、考えていく。

iとjが同じ場合、1/4弱はNoとなるので、乱択でそういうのを見つける。見つけた小さい要素を使い、全体に対して質問をして2つに分ける。クイックソートみたいにできないかなと。分けた大きいほうはよくわからないので、小さい側をどんどんやっていって最終的に長さ2とかになったときを考えてみる。すると、1を見つけることはできそうだが、1は2個足しても2より大きくはならないので、2を見つけることは難しそうだとわかった。ここで、1という小さな定数を使えば単に2つの要素の比較ができると気づいた。iとjが同じ質問もiとjが異なる質問も使うんだ。なんてすごい問題なんだと思った。

方針としては、インデックス(質問に投げる数)をソートする。結局は必要なさそうだったが、乱択を考えていたのでインデックスをシャッフルしておく。また、N=1で停止しないコードになりそうだったので場合分けしておく。まず1を見つける。乱択でN/2以下の要素を見つけて(必要なかったか)、それを元手にそれの1/2以下の要素を探すのを繰り返す。1/2以下の要素がなくなったらそれは1だ。大きいとわかった要素は調べなくていいので全体でN回程度の質問で済む。1がわかったらあとはstable_sort(マージソートはどんなケースでも比較回数が少ない)に投げるだけ。これでインデックスがソートされたので、元の順列を求めて出力すればいい。

時間があれば手元で動作確認できる方法も思いついていたが、そんな時間はないのでN=2やN=3を少し試して提出した。手でてきとうに返事してると終了しないプログラムなので、提出して確かめるしかなかった。いくつかACがあれば、普通にデバッグすればまだ望みがある。で、ACだった。終了10分前。ちょうど1時間かかっている。

(追記)解説見て考え直すとかなりシンプル。1を見つけるのは、最小値をN-1回更新するだけみたいな感じだし、あとはswapで1を先頭に持ってきてstable_sortするだけ。動作確認も、自分でシャッフルした順列を用意してそれを使って質問に答えるようにすればいい(質問回数もカウントできる)。