ABC339

6完3ペナ。Dで破壊されてパフォーマンスが落ちた状態でEをやったが、Eが簡単で結果的にはFも解けたしDも通ったしGは全然だったので、そこまで影響はなかったかな。でもこういうDは大嫌い。解法はすぐ見えるのに実装に時間と体力(集中力)が必要で、つまらないうえに他の問題を楽しむための時間や体力も奪われる。今回は実装できると思ってやったけど、面倒そうならとりあえず次の問題を解くというのがいいと思った。Dをやらないのではなく、Dを後回しにする。健康な状態でEをやったほうが楽しめる。

A - TLD

分割してできた文字列の列の末尾の要素ね。「末尾の文字列」とだけ言われるととっさには何のことかわからなかった。後ろから'.'を探して、見つけたらsubstrで次の文字から最後まで。これは1分ちょっとで通せていればよい。

B - Langton's Takahashi

あー問題名見てなかった。ラングトンのループは知ってたけど、ラングトンのアリなんてのまであるのか(なんで知らなかったんだ?)。

Bにしては実装が重すぎる。まあでもBに置くしかないよなあ。後半の問題で使うための基礎という意味ではいい問題だし、ちゃんと配点も250点になっている。

自分は1回か3回、回転させてたけど、解説のように向きを4個準備しておくのもあったね。回転方向は添え字ガチャに頼った(2通りしかないとわかっているので使っていい)。

C - Perfect Bus

いやこれ実装は簡単だけどちょっとドキドキするよ。けっこう難しいと思う。人数の増減をグラフに描くと、最初の人数によらず同じ形。一番低い場所が0になるように上下位置を合わせる。適当な人数から始めて一番低いところを求めて最終的な人数からそれを引けば答え。負の数を引くのがちょっとややこしい。

D - Synchronized Players

Nが小さいのでN^4サイズのBFSができる。2人のプレイヤーの位置はちゃんと配列にしたり、はみ出さないようにする処理にclamp使ったり、ちゃんと工夫した。ただ、こんなのに20分以上かけてる不快感と実装による疲労で精神はズタボロに。しかもWA。ちょっと見直してEへ。

EFを通して戻ってくると、なんかBFSで距離を入れる配列がcharだった。これ最初は訪問フラグみたいなつもりだったのか、答えが128未満だとなんとなく思ってたのか、意味わからんcharだ。intにしてAC。60^4は10^7を超えてるから(実行速度のために)メモリ節約したい意識は確かにあった。答えの最大値どのくらいなんだろね。自明な上界が60^4だからなあ。

E - Smooth Subsequence

A_iを末尾とする部分列の長さの最大値でDPしたい(そこより左でどうだったかが関係なくなるからDP)。A_iが小さいし値の範囲を見たいので、セグ木を数列のインデックス方向ではなく数列の要素の値方向にとる。現時点で部分列が各値で終わるときの長さの最大値を入れる。同じ値が出てきたら上書き(左から見ていって、悪くなることはない)。初期値は0。

Flat Subsequence
既出だったらしい。このコンテストは自分も参加してブログも書いている。当時より短い時間で解けてよかった。当時と違ってmax_elementでセグ木のサイズを決めている。

F - Product Equality

A_iが小さいなら普通にできるんで、何か工夫できるんじゃないかと考える。ただ、N=3だとしてもそれなりの計算量だから、ちょっと先が見えない感はあったんだよな。答えが実は小さいとかも思ったけど、2^0から2^999まで揃えたらめっちゃ多いよね。なんか問題の見た目から期待しちゃったんだよな。何か自分の気づいてないいいものが隠れてるんじゃないかと。で、下9桁だけ見て同じになりそうか判定できるなとか考えてたら、あーそういうことかと。mod 2^61-1で提出してWA。そこにmod 2^64も加えてまたWA。しょーがないので1.4*10^9くらいの素数を2つ見つけて使ってAC。AtCoderでここまで色々なmodに対策してるのかなり意外だった。感覚にない。甘えた自分が悪いのはそう。

(追記)たまたまこの日の昼間にGMPを使うコードの見直しをしていたので、GMPを使うことは思いついた。それがよくなかった面はある(普通に考えればAtCoderで多倍長演算要求してくるわけないのに使おうとしてしまった)。で、GMPを使えば愚直が通った。まあこれはコンテスト中思いついてもやらないのでいい。

G - Smaller Sum

オンラインでやることを強制する方法に感心する(さすがに知ってて忘れてるだけな気がするんだよな)。なんかWavelet Matrixみを感じる(だとしたら今の自分にはできない)。平方分割が解法だったらやらなくていい(時間が潤沢にあったらやったかも)。終了後、オフラインなら解けることを確認したが、もっと早くやったほうがよかったか(けっこう不可能感出てくる)。

(追記)普通に解説AC。セグ木を改造して作る。各ノードは、ソート済みの列とその累積和を持つ。末端たちにAを入れたら、構築はセグ木と同じ要領で、ソート済み列なのでstd::mergeが使える。和を求めるときはstd::upper_boundで求めた位置の累積和を使う。