ABの二完。
Cで桁DPをバグらせ続けた……。
No.3242 Count 8 Included Numbers (Hard)
下の桁から桁DPしようとして長い時間をかけてしまった。
求めたいものを二つに分離し、
・calc(keta,minus)でN[:keta+1]-minus以下の8を含む個数
・calc2(keta,minus)でN[:keta+1]-minus以下の個数(つまり、N[:keta+1]-minusの値)
をそれぞれ桁DPしようとしたらなんとか書けた。
下の桁から桁DPをする場合、Nという数字を明示的に持っても間に合う場合は簡単に書けるけど、繰り下がりの処理をちゃんと書いてやらなくてはいけないときは結構大変になってしまうのかもしれない。
No.3243 Multiplication 8 1
行列累乗と言われてAC。
コンテスト中この問題は読んだのに、DPで求められることにすら気付かなかった(組み合わせ的な何か? と考えていた)のはショック。
No.3244 Range Multiple of 8 Query
三桁の8の倍数を全探索し、rより以前にある数字を二分探索で探し、貪欲に使っていく……という方針は思いついた。
が、一桁や二桁の場合に気付かずWA。テストケースを見て気付き変更したがTLE。ChatGPTにC++に直してもらいACした。
C++に直しても制限時間ギリギリでなんで? と思ったが、二分探索が不要だったよう。各indexについて、0~9それぞれの数字がどこのindexにあったかを三つもっておく、というのは二分探索を使わなくとも前計算できる。
気付かなかったけど、確かにそうですね。
No.3245 Payment with 8-rep Currency
自力AC。
小さいものについては全探索し、大きい値については、作れる(8で割ったとき)互いに素な二つのものから作るという方針。
(1, 1, 1, 0)で123が、(2, 1, 2, 0)で235が作れ、この二つは互いに素であり、拡張ユークリッドの互除法を使うと、
・123 * 107 - 56 *235 = 1という式が得られる。
これを使って不定方程式を解くと、Nについての一般項が、
x=107*N -235*k
y=-56*N+123*k
(kは整数)
となるので、これらを満たして0以上になるような最小のyを求め、その(x, y)のときに条件を満たすことを調べればOK。
自然な解法かと思ったが、ツイッターを検索したところ拡張ユークリッドの互除法と書いている人はいなそうだったので、珍しいのかも。
No.3246 80% Accuracy Calculator
非常に苦労し、提出してエラー出力結果を見ることを繰り返してAC。
最初は、「+ A C C」みたいなのも許されると思ってなんでREなのかと何度も提出してしまったし……。
足し算が100%成功するとした場合、
「A B 0」を「0 B 0」とした後、
「B B 0」「B B 2B」「3B B 2B」……とBずつ加算していく方法が考えられる。(最初にどちらにBを加算するかは偶奇で分類)
足し算が成功しているかを適切に判断した場合(自分は、六連続正解が出たら採用、とかした)、これでもギリギリ回数が間に合ってしまいそうなのが迷うところ。だが、実際はこの方針で間に合わせるのは無理なんだと思う。
なので、
「B B 2B」「4B B 2B」「4B B 8B」……と、2ベキのBを作ってから、Bずつ加算していく方針でACした。
しかし、解説を読むと、繰り返し二乗法のようにやればもっと早くできるようで。タグに「繰り返し二乗法」とあるのは見ていたのに、気付かなかった。