ABC186

うれし~。パフォーマンス2311でレーティングがめっちゃ高くなった(今回黄色になる(Good Bye rng_58に出る)のが不可能なのは知っていた)。前回のパナソニックと違って雰囲気は普通だが、その実かなりクセのあるセットだったと思う。Dがすぐには全然わからず、Eは簡単なコードで解けそうだが自分にとって短時間で解くのは難しそう、Fが解けそうだったのでFから解いた。次に2000人以上解いてるという情報を使ってDを解き、最後に余裕ができた状態でEを適当に片付けた。DEを頭に入れてFを考えられたこと、考察に自信の持てないEを最後にやったことで、時間を稼げたと思う(この順位だと時間が更新後レーティングにかなり大きく響く)。

A - Brick

割るだけ。サンプルもそんなに強くないし、本当に切り捨てでいいかはけっこう確認した。

B - Blocks on Grid

グリッドの意味はない。「追加してはいけないとは書いてないよな」と思いながら、取り除くしかできないなら最小に合わせることになるので最小値と総ブロック数を求めて、総ブロック数から最小値*マス数を引いたのが取り除く対象。

C - Unlucky 7

ちょっと考えるけど、愚直が通る制約なので愚直。XがB進法で7を含んだら0そうでなければ1を返す関数を書いた。

D - Sum of difference

要するに(A_iを順に追加していくイメージで)これまでに追加された数たちと自分の距離の和を足していく。絶対値だから自分よち大きいのと小さいのに分けて総和を求めたい。std::setとかでも無理そう。自分を増減させたとき上下にある要素の個数の差で、求める和への寄与が決まる。妙なわからなさなのでEへ。

Fを通したところで初めて順位表を見てDをやる。順位表、結果を求めるなら見たほうがいいと思うけど、難易度を知らずに挑んだほうが楽しいという面もあり、そのバランスがとれるタイミングをはかっている(そんなに難しいバランスではないので大体いつも満足できている)。

これはあれだ、ソートしてもいいやつだ。順に追加していくイメージに引きずられすぎた。自分との差は0なので、単に自分以外の全員との距離の和を求めて2で割るだけ。総和を求め、ソートして、小さい順に見ていって「これまでの要素数*自分の値-これまでの和」を足していく。同様にこれからの和とかも使って足していくが、今気づいたけどこれ要らないじゃん、ソートしたら追加していくイメージでいいんじゃん、そしたら2で割る必要もないし。エアスポットで緩急付けられたらさすがに最適実装できないね。

E - Throne

まあこれは簡単に解けそうなんだけど、自分が短時間でできるわけではないので困る。明らかに解ける見た目をしてるんだけどね。とりあえずFを読んでおく。

他は全部解けたので落ち着いて考えよう。この時点でかなりいい順位。瞬殺できればそれを保てる。解法は見えてないので、思いついた部品をとにかく使っていく。最短手数は置いといて、NとKの最大公約数だけ移動することは可能だろう。それで移動できないところへは行けないだろう。ということで-1判定はできた(書く)。そうするとS, N, Kは全部その最大公約数(Gとする)で割り切れるから割る。SをN-Sで置き換えて移動したい個数とする。忘れてたけどKをK%Nで置き換えてN未満にしておく。で?X回で達成できるとして、K*X=S(mod N) なんだよね。XがX+Nでも成り立つ(Xもmod Nでわかればいい(当時は「Xはなんか周期がある」程度にしか考えてなかった))。安直に考えればKの逆元をSに掛ければいいが、Nは素数と限らない。でも互いに素ではあるので、ユークリッドの互除法的な逆元求めるやつは使えそう。逆元掛けてNで割ったあまりを求める。サンプル通ったのでさっさと提出してAC。戻ってきてからは10分くらいだったので十分速い。

F - Rook on Grid

飛車と言いつつ左や上には動けないが、2手しか動かないので影響なさそう。すると、右へ動いてから下へ動くか、下へ動いてから右へ動くかしか有効な動きがない。片方だけなら簡単だ(その行で一番左にある障害物を前計算しておく)。両方なので、どちらからでも行けるマスを数えようと思った。考えているうちに、右=>下だと行けないけど下=>右なら行けるマスをカウントできそうだと気づく(今考えるとどっちでもよかったか)。i方向を主体にしたいので下=>右で考える(これは書き始めの段階ではどっちが好きなスタイルかわからないので賭けだ)。(0-indexedで考えて)初手で(i, 0)へ移動したときに2手目で(i, 0)から(i, a[i]-1)までのa[i]マスに移動できるとする。右=>下で(i, a[i]+1)から(i, a[0]-1)までのマスのうち何個に行けないかは、上から見て最初の障害物がその線分の上に何個あるかと同じなので、解けそうだ。解けそうなのでFをやることにした。

最初は累積和だと思っていて実装もしたが、どうも違う。2次元は思ったよりややこしい。頭の具合がはまってるときのそれで不安になるが、Cまでを7分で解いている前半が簡単な回だったのでまだ時間はたっぷりありそれほどの焦りはない。最終的に、「上から見て最初の障害物」を縦位置でソートして順次BITに加えながら範囲内の個数を得ていくという方法になった。初手で行けない範囲のiは場合分け。初手で右や下に移動できないケースも考えて大丈夫なのを確認。かなり迷走した(提出コードに「unused parameter ‘i’」という警告が出ていることからもわかる)。思ったより時間がかかり、途中で「こうなるならDEを先にやったほうがよかった」と思ったが後の祭り、最終的には50分で通ったので結果オーライ(Fからやってよかった)。