DDCC2019本戦

良い環境で挑むことができ素晴らしいコンテスト体験だった(結果が出たからそう思うだけかもしれないけど)。

A - レース (Race)

読むのにかなり時間がかかる問題。意味がわかれば簡単で、氷をできるだけ長くするだけ。長いのを長くしたほうが効用がでかい。雪が連続する制約なのは氷が結合しないようにしてくれてるのだ。両端もわかりやすくなってる、ことには気づかずコードを書いて、考えに詰まったとき制約の意図に気づく。読んだけど忘れてるんよ。問題文を何度も読んで経験値を溜め意図がわかったところで書き始めるから。計算量は気にせず、ソートで。サンプルで気づいたコーナーケースも汚く対応。

B - 大吉数列 (Array of Fortune)

転倒数みたいな?K以上大きいやつが左に何個あるか(これを表す数式がなかなか読めなくてなあ)。組の個数が最大になるケースを考えてみる。数を大きい順に並べて、5 4 3 2 1。K=2として、1の上に小さく3 4 5と書く。2の上には4 5と書く。3の上に5。3+2+1の三角形。それより大きければ実現できないとわかる。それ以下なら必ずできると予想し、実際できそうだ。どっちかから見ていけば貪欲が行けそうと思い、大きい順に挿入していけばいいと気づく。最終的な組の数だけでなく、各A_jに対する組の数まで指定できるのか!?そんな都合のいいことあるかと不安になるが、できるようだ。あとはオーダーを下げるだけだが(未だに解けてないのだが)、他の問題を考えることを優先し、部分点をさっさと取る。

D - DISCO!

これは、思い出せないけど最近見たやつだ(このブログを「累積和」で検索すると、k-DMCだった)。典型だから点数下がったのか?(直前に900点→700点と変更された)他の問題も一応読むが、この問題が狙い目と見て深く考える。2^32は、uint32_tで計算するだけなので楽。ただ、記憶にある累積和は段数が少なかったが、これは5文字もある。とはいえ強い人は瞬殺なんだろうなあ(順位表を見ると早い時間にDが解かれている)。しばらく考えて、向きを決める(詳しくは忘れたが、たぶん後述する「まとめて見れるやつ」が前に来るか後に来るかで前のほうが引き算要らなくて楽)。Dの個数の累積和を持ち、Iがある場所についてDの累積和を足してく累積和を持ち、以下同様。Oの累積和で、その区間で終わるDISCOの個数がわかるようになる。あとはそこから、その区間で始まらないDISCOの個数を引くだけ。区間のOの個数*区間より前のDISCの数でいいか?それはさすがにない。区間のCの数*区間より前のDISの数も引かないと。そういうのをやってもサンプルが合わない。かなり試行錯誤した(ちゃんと考えろ)。正解と比べて多いのも少ないのもあるので根本的におかしい。

時間制限が13秒というのを見てギョッとする。あー、ひょっとして累積和は(文字数5をkとして)k個じゃなくてk*k個要るのか?正確にはk*(k+1)/2個ね。区間のOの個数*区間より前のDISCの数、これはいい。区間のCの数じゃなくてOから見たCの延べ個数だ!それをループでk-1回引き算してサンプルがなんと通ったので提出。普通にWA。何が違う。いつの間にか符号付き乗算されてたんじゃないかとは疑った(違った)。いや確かに違う。Cの延べ個数の時点で区間より前にあるCもカウントしてる。区間より前のDISの数とかは大丈夫。そもそもこの問題、区間が全体であれば簡単。[0, r)という区間でも同様というか、累積和にそのまま答えが入ってるから簡単。問題は区間のCやSやIの数。ただ、よく見ると1文字短い問題に帰着されている(区間のCOの数とか)。なので、全パターンの累積和さえ持っていれば最悪再帰でできるんじゃないかと思った。結局そのように書いた。ググってラムダ式再帰。混乱してバグに苦しみつつ(実際はワンチャン通れと色々試行錯誤してる)なんとかAC。再帰はすごいね。なんで解けるのかよくわからなかったが、とにかく小さい問題に帰着できて一番小さい問題が単なる累積和で解けるとわかっているから、解けることもわかるのだ。わからないのにわかる。

(2021/4/9追記)累積和a[x][y][i]には、"DISCO"のx文字目からy文字目までがSの最初のi文字に何個あるかが入っている。これを使えば[0, R)のDISCOの数は簡単で、そこから[0, L)に'D'があるDISCOの数を引くという方針。[0, L)にある"D"の数と[L, R)にある"ISCO"の数を掛けたもの、...、[0, L)にある"DISC"の数と[L, R)にある"O"の数を掛けたもの、[0, L)にある"DISCO"の数、という5つを引けばいい。このうち難しいのは"ISCO"の数などだが、これは再帰的に同じ問題を解けばよい。再帰せずに求めるには、[L, R)にある"O"の数は累積和でわかるので、"CO"の数、"SCO"の数、"ISCO"の数、と順に求めていけばいい。