101. 今日解いた問題(2022.04.13)
問題一覧
- D - Remainder Reminder (Diff: 1129)
- F - Programming Contest (Diff: 1423)
- D - Base n (Diff: 1425)
自分の解法など
D - Remainder Reminder
入力例 1 で考えてみます。観察すると、 であることが分かります。よって、この範囲でそれぞれ が何通りあるか考えるのがよさそうです。
で剰余がループすることを考慮して、 回は全体を取れてそれぞれ 個適切な が存在します。つまり、 個足せます。余った分()が 以上ある場合、ここから条件を満たすものだけ足します。
計算量は です。
F - Programming Contest
DP っぽいですが、 と制約が大きいので無理です。 が小さいことに注目すると、全探索っぽいです。 をそれぞれ解く・解かないの全探索が思い浮かびますが、 なので 個の状態が出てくることを考えると、これも不可能です。
ここで、探索範囲を限定できないか考えます。2 つの部分集合に分割してそれぞれの総和パターンを算出し、組み合わせから最終的な総和パターンを出してもよいと気付きます。つまり、半分全列挙の問題です。
実際、 で、部分集合の総和算出はこれを 2 回行うだけなので間に合います。部分集合内の要素に限定した総和集合の算出が です。こうしてできた 2 つの部分集合から元を 1 つずつ選んで足せば、最終的な総和パターンを列挙できます。今回は足して 以下の最大値を探したいので、どちらかの部分集合をソートしておき、足して 以下となる最大要素を二分探索で求めればよいです。
以上より、計算量は 、つまり です。
D - Base n
考察すると、条件を満たす最大の を とすると、 なる は全て条件を満たすことが分かります。また、、 なので、 です。よって、 で二分探索して を求めれば、 が答えになります。計算量は です。
…ただ、これだけだとこんなに高diffにはならないわけで、この問題は厄介な落とし穴が 2 点あります。
オーバーフローを考慮する
を 進法表記とみなしたときの値を愚直に算出しようとすると、オーバーフローが容易に発生します。頑張ってオーバーフローを検出するのも手ですが、 を 進法に変換して と比較すると、除算しか発生しないのでオーバーフローを防げます。
問題をよく読む
これサンプルに無いの結構意地悪だと思うのですが、よく読むと「 の種類数を求める」のではなくて「 を 進法表記とみなして得られる値の種類数を求める」問題となっています。
何進法でも 1 桁目は に対応するので、 のとき得られる値の種類数は なら 、そうでないなら です。これだけ例外を書いておきます。
ちなみに、私は最後まで問題の誤読に気付けず、8回くらい WA を出したところで諦めてテストケースを見に行きました。そして、 のテストケースで考えていた解と異なる値が想定されているのに気付き、唖然としました。