公式解説では二分探索をうまく適用する賢い方法がとられていますが、私はそんなこと思いつくわけもなく…
しかし、気合で数え上げることによってコンテスト中にACできたので解法残します。
解法
個以上リンゴが載っている皿のみ、小さいほうから考える。
もし、個以上リンゴが載っている皿の枚数とその中で最も少ない個数(= とする)の積が以下であれば、周分個ずつリンゴを食べるのでなく、周分は個食べるとみなすことで、回の操作につき枚はリンゴの乗っている皿を減らすことができる。
また、以降の周についても、前の周で一度に減らしたリンゴの個数をゲタとして管理し、ゲタを外すことによって同様に計算ができる。
もし、と残りの皿の枚数の積がより大きい場合は、残りの皿について均等に減らせるリンゴの個数は少なくとも未満のため、と残りの皿の枚数から愚直にシミュレートできる。(具体的には、残りの皿の枚数との商を残りの皿から引き、ハンパはインデックスが小さいほうからづつ引けばよい)
そこで、個以上リンゴの乗っている皿について、皿のインデックスとリンゴの個数をヒープで管理し、以下のような操作を行う。
- ヒープから乗っているリンゴの個数が最小である皿の情報をpopする(=リンゴの個数を, 皿のインデックスをとする)
- ゲタを、残りの皿の枚数をとし、の場合はをに更新し、からを引き、新たなゲタをに更新する。そうでない場合は、取り出した情報を戻したうえで、操作をやめる。
- 操作後になおもが以上である場合は、上で述べたとおり、残りの皿の枚数との情報を使って、愚直にの値を更新する。
実装上の注意として、の操作時にが以上であることと、皿の枚数を以上であることを確認しないと、を皿の枚数で割った場合に除算起因のREをもらうことがある。(具体的には、であればそのようなことが起きうる)
上記解法は、ヒープを用いて操作をシミュレートする箇所がボトルネックになるので、程度で動作し、十分高速に動作する。
実装は以下の通り。