ABC255

6完。今週は苦しみながらも色々やれてよかった気がする。そこへ突然現れるABCは、久しぶりに感じられた(普通に1週間ぶりだけど)。

A - You should output ARC, though this is ABC.

簡単だけどさすがに実装量が多く1分以上はかかった。

B - Light It Up

Bで二分探索うそだろ!?なんとか頑張ってBらしい解法を探る。明かりを持っていない人の視点で考えると、その人が照らされるためにはRが一番近くの明かりを持った人までの距離以上である必要がある。最小値の最大値が答えで、実装がけっこう大変。Kは0でもNでもないので最小値や最大値を求めるときに気を使う必要はない。

C - ±1 Operation 1

一番近い数までの距離。まず、数列の要素の絶対値は2*10^18以下に収まるのでlong longで大丈夫。数列の最小値以下のときと最大値以上のときを場合分けして処理。そうでないときはDが0でないので割り算できる(書きながら気づいたというのもあって、0でないとわかっていても明示的には書いてないのでドキドキするね)。割って掛けてX以下の最大の要素を求めるときに、Dが負の場合をケアしようとして、Aが数列の最小値と限らないことにようやく気づく。これは数列の頭とお尻を入れ替えればいい。あとはX以下の最大の要素とその次の要素の近いほうの距離を出力すればいい。

D - ±1 Operation 2

C問題と同じ設定だが、制約も内容もかなり解きやすそう。Aはソートしてもいいのでソートすると、X以上とそれ以外に分けて累積和のアレだ。ソートして累積和を求めておき、各クエリに対しては二分探索で初めてX以上となる位置を求め、あとは図を描いて引き算で2箇所ぶん求める。

E - Lucky Numbers

何言ってんのかわかんないが、Aとしてありえるのは自明な解からジグザグに伸ばしていったものたちだけだ。それがXに当たるの検出する?最大値になるときはどれかは当たってるから各A_iがX_jに一致するのを全探索?A_iがX_jに当たったときの伸ばした量はわかるので、伸ばした量として現れるもの(A_iとX_jの差をインデックスの偶奇で符号を変えて)の個数を数えればいい。同じ伸ばし量で同じA_iが複数のX_jに一致することはないことに注意(コンテスト中の思考って特殊で、これをどう捉えていたか思い出せない)。

実装が楽なunordered_mapを使った(楽じゃないのはソートしてランレングス)けど、logみたいの(Mとunordered_map、どっちもlogではないけど)が2つ付くことを忘れていた(1つだと思ったから躊躇わずunordered_mapを使った)。実行時間が538msと思ったより長くて気づいた。実行時間制限が4秒なのもあとから気づいた。

F - Pre-order and In-order

帰りがけと思ってたら通りがけ順だった。そういうのがあるのか。方針として、オイラーツアーで上からからぶあっと考えるか、正面からパズルを解いていくか、前者を有力視していたけど普通に正面から行けたわ。まず、Pの先頭が根。Iの中でそれが現れる位置でIを前後に分け、前が根の左の子、後が根の右の子。Iの前の部分がPでも根に続く連続した区間で集合として同じになっている必要がある。そうやって分割統治みたいにしていく。実装としては、集合として同じかのチェックにハッシュを使い、前と後で小さいほうだけを比較する(これでlogくらいに収まるやろとかテキトーに考えてた)(集合として等しい状態で関数を呼ぶことを保証する)。根がIのどこに現れるかは逆引きテーブルを作っておく。Iの逆引きした位置から開始位置を引いて前側の個数を求める必要があるなど、混乱要素が多い。

これ集合として等しいか毎回チェックする必要ないかあ。その場合、根が区間内のIにあることは保証されないけど。なんか今回EFで時間をかけてしまった気がする。

GHは読んだだけ。Hはやたらスケールが大きくて面白そうだった。