ABC118

終了後測ったら37.0度。(開始直前に)なんか緊張してるとは思った(ウンコは解き始まったら引っ込んだ)。昼間は何ともなかったんで、ABCによる発熱かなあ。自分にとってはratedでもないのにそこまで意識するか。コンテスト中は、熱がある感じはしてなかった。

A - B +/- A

「AがBの約数なら」というのがどっち向きなのか全然わからない。「12が4の約数なら」と書いてあれば約数じゃないなとすぐわかるという自覚もある。人間の悲しさだ。まあ少し考えてコードを書く。この問題ちょっといじわるだよね。Aが約数ならBより大きくないからB-Aを計算するのが自然に思える。

B - Foods Loved by Everyone

問題文のA[i][K[i]]がパースできない。サンプルまで読み進めれば雰囲気はわかるので実装する。「全ての」という条件だから、一つでも例外があったらダメというコードを書こうとするが、与えられるのは好きな食べ物のリスト(好きじゃないリストではない)なので、カウントしてN票得たものの数を出力する。「全ての」って書いてあったら、例えば何のアレルギーがあるかのリストが与えられて全員が食べれる食べ物の種類数を答える問題だと思うじゃん。これは逆なんだね。面白い。

C - Monsters Battle Royale

この問題の状況を表すのに「ランダム」という言葉を使うの、俺はわかるけどわからない人もいるんじゃ?とか思ってた。サンプル1のように最小のAを残すことはできるし、2が9に4回攻撃して1を作ることもできる。要するに最大公約数。それでいいか?最大公約数は作れることと最大公約数より小さくできないことを示せばいい。ぐるぐる。AtCoderで、(実装に)全くひねりがない問題って珍しいのよね。それで不安になって例外がないか1分くらい考える。なさそうなので提出、AC。証明できないの本当に弱い。

D - Match Matching

ナップサックか?と思って頭が真っ白になった。いつの間にか10分過ぎていた。DPが苦手すぎる。俺も思考停止DPしたいよ。でも思考停止DPしてる人って問題をちゃんと解けてる人だよなあ(少なくとも自分の場合はそう)。

落ち着こう。まず、桁数が最優先だ(最初、大きいAから並べようとしてた)。ある数より桁数が少なくて大きいということはない。次に、その桁数を実現できる中で、max(A)の個数を最大化する。以下、j番目のAの個数を最大化というのをM回繰り返せばよい。長い。見通しが立たないと俺の性能が著しく落ちる。まず実装しろ。自分にとって時間がかかる問題は、間違い(TLEするとか一部の条件を満たさないとか)でもいいから早めに実装するのがいいのではないかと最近思っていた。コーディングは思考が強制的に整理されるし、正しい解法を思いついたときコードを流用できる可能性も高い。でも、解けないうちは考えたくて、それはできなかった。ムーブが弱い。

実現できる最大の桁数はDPで求まりそう。問題は、特定のA_i(当時はiだったが後にj)の個数の最大化だ。桁数はもう決まっているので、その中でどう最大化するか。もう1回DPをする。残りの数で実現できる桁数を列挙して、いや、マッチ棒の数も決まっている。頭の中で、桁数とマッチ棒の本数の混同が頻繁にあった。DPをちょっと変更して、そのマッチ棒の数で実現できる最大桁数とする(今考えると変更前のDP何の意味があるんだ?(そのためにも実装すべきかあ)(こういう混乱してた問題はブログ書くのがほんとにきつい)(そもそも、理屈に合った思考をしてるならとっくに解けてる))。そもそも、理屈に合わない自分の思考をブログで再現する意味とは。

桁数が決まっていて、その桁数を実現できるmax(A)の最大個数がわかるならそれでいい。しかし、当時は残りのAたちでその余ったマッチ棒の数を作れるかしか判定できなかったので、その状態で貪欲に各Aの個数を決めていくと、最大桁数にならないことがあるんじゃないかと思っていた、のかな?んー、作れる最大桁数のDPでいけるか。最大桁数は求めてあるので、それを超える心配はない。より小さいなら突っぱねることができる。じゃあこの方針でも行けたのかな。

ダメなケースがありそうと思っていたのに加え、DPを何回もやるのがいかにもやりたくない形。そこで、全部DPで済ますことを考える。「最大桁数」ではなく、「最大桁数とそれを実現する辞書順最大の各Aの個数(表現がよくわからん、頭の中にあったものを文字にできない)」とする。std::arrayは先頭から順に比較してくれるというのを(知っているのはわかっているので)思い出し(わかりますか、この思い出すは「あっ思い出した」じゃなくて、場所がわかっている引き出しを頑張って開けている)、比較できる構造体を書く。Aは大きい順にソートしてあって、意外にもそのままの順番でいい。j番目のAまで使った、各マッチ棒数の最善を更新していく。更新するときに、最善なものから遷移すれば最善になるという性質があるので大丈夫だと思った(自信なさすぎる)。このDPは、よくあるDPのように後ろからやる必要はない。同じAを何回でも使えるので前からやる必要がある。サンプルが通らなかったが、その様子から、「ちょうどi本で作れる最大桁数」と「i本以下で作れる最大桁数」のDPを間違えている可能性が考えられる。それだった。この2つは、何が違うのか何回も考えて毎回忘れてる。今回は、初期化が必要なDPだったね(いつもは必要ないDPが多い)。「ちょうど」のほうのDPなので、-1でその要素を無効化するようにした。なんとか1時間で全完。

変数名をけっこう変えた。桁数とマッチ棒の数がごちゃごちゃになってた。簡単そうだとはそれなりに早い段階で思っていて、解けない心配はしていなかったが、早解きもできる気がしなかった。時間がビュンビュン過ぎてた。