ABC233

6完。今は、コンテストと軽い復習でしか競プロをやっていない感じ。実力はそう簡単に落ちるものではないが、やはり慣れというかスムーズな立ち回りができないという意味で少しだけ不利かもしれない。GH(Hは今回からEx表記)が難しく、「コンテスト時間がもっと短ければいいのに」と思う状態になってしまい残念。前回まででレーティングが5連続狭義単調減少だったけど、記録更新はならず。

A - 10yen Stamp

貼る必要がないことがあるのがかなり怖い。maxを使えばよさそうだけど、なかなか確信が持てなかった。切り上げなのも地味に嫌。

B - A Reverse

これは0-indexedに直してreverseするだけ。

C - Product

かなり難しそうな見た目だが、よく読むと愚直に数えろと言われている。どの箱も2個以上のボールが入っていて総積が10^5以下だから、Nはけっこう小さい(だからどうということはないけど)。積はオーバーフローする危険性があるため、整数で掛け算する前にdoubleでやって1.5e18を超えたらスキップする。0が含まれていないのは良心的。

解説を見て。オーバーフローを割り算で確認するやつ難しそうに思えて避けた。

D - Count Interval

えっ負の数もあるのと一瞬戸惑う(見た瞬間頭がしゃくとりになってる)が、トイレに立つと累積和でいいと気づく。右端の位置を右に動かしながら対応する左端が何通りあるか数える。K=0のケースが気になる(幅0の区間もカウントしちゃうとか)が、処理の順番をちゃんと考えれば問題ない。std::mapを使い、累積和でここより左に何が何個あるかを管理する(unordered_mapちょっと思ったけど最終的には忘れてしまった(順番を使う場合もあるから最初からunorderedに決めて進むのはやりづらい))。

(追記)定数倍軽くしたいなら座圧でもいい。

E - Σ[k=0..10^100]floor(X/10^k)

サンプルにあるように書き下すと意味はわかる。10^100でやや混乱したが、Xの桁数より大きければそれでよかった。いろんな向きで切ってまとめてみると、桁和は高々50万*9で7桁以下なので、それを50万回足し算して間に合う。楽な実装が何か、ずっと考えててそれがメインの行動だった。

(追記)1桁増えるかもしれないぶん1だけずらして先頭(上位)からやると楽だった。上からなので桁和を予め求める必要もない。現在の桁和に、今までの総和の今見てる桁を足して10で割ったあまりをその桁に戻す。10で割って、0になるまで繰り返す。コンテスト中に書いたコードは、10で割るのと別に繰り上がりの処理もしていた。終端は決まっているのでそこまで全部に'0'を足して先頭が0かどうかで出力の開始位置を変える。

F - Swap and Sort

手でやっていて、木構造が見える。UnionFindで全域木をとってそれで考えればよさそう(スルーした辺がないせいで50万回に収まらないということはなさそう)。辺を使った順番は、辺に番号を持たせておいてDFSの行きがけ順に記録するとかでよさそう。グラフで行ける見通しが立った(立ったは言いすぎかな)ので書き始める。そうしているうちに、端から処理しないとダメなことに気づく。考えが整理されて実装が完了する見通しが立つ。パスグラフではなく一般の木であることで損することはない(次数が1の頂点から決めてその後頂点を削除すれば(木の頂点数-1)以下のスワップで済む)。頂点を1からNまで順に見て、次数1を見つけたら自分を削除して隣の次数を1下げる。そのとき頂点番号と入ってる数が違ったら、それがどこにあるか愚直に探索してそこから今の場所へDFS。DFSでは、潜るときスワップと使った辺のpush、戻るときスワップと使った辺のpopを行う。行き先の頂点に着いたらそこからは何も操作(スワップとか)せずに戻ってくる。ループがめっちゃ重なってて計算量がわかりにくいが、何重になっていようとそれぞれの処理がO(N^2)なので全体でもそれら定数個の和のO(N^2)になっている。

UnionFindを使うのを忘れて1RE(WAも多数)。操作回数が50万回を超えたらREになるようにしていたのが少しは役に立った(しかしメモリ使用量には気づいてなくて、これ再帰でMLEした結果のREだったかもしれないな)。

(追記)DFSの中でDFSすればよかった。自分の子孫を全部処理してからやればいい。

G - Strongest Takahashi

解けそうな見た目だけど考えれば考えるほど無理になっていく。大きいのをある程度貪欲に分割できないかと思ったけど、2個以上に分割できるものが2個に分割できるとは限らないみたいだし、できる分割をしていいという仮定すら必要になりそうで、無理と思った。

解説の冒頭を見て。DPという発想はなかったな(そこからも難しいんだろうけど)。「どうやっても無理そうならDP」という格言が身に付いてない。

(追記)間違ってた。正方形が重なることがあると思っていたけど、そうすると両方を含む正方形よりもコストが大きくなるので、重なることはない。分割は、正方形で考えていたけど、長方形でならDPできる。長方形の個数はO(N^4)でしかなく、更新にO(N)かけても間に合う。分割してコストが減るときは必ず空行(空列)があるというのもわからなかった。見慣れぬ場所でその場の物理法則を理解するの、相当な力が要る。