かしのブログ

競技プログラミングとか

第二回 アルゴリズム実技検定 M - 食堂

問題

ある食堂では i日目、 i + D日目、 i + 2D日目 \cdotsに料理 C_iが提供される。 社員 i(1\leq i \leq N)それぞれについて、以下の条件で食堂に通うとき、 T_i回目に利用するまでに料理 K_iを食べる回数 A_iを求める。

  • 初めて食堂を利用する日は F_i日目である。
  • 初めて食堂を利用して以降、料理 K_iが提供される日は必ず食堂を利用する。
  • 初めて食堂を利用して以降、前回の利用から L日経過しているなら利用する。

atcoder.jp

考察

各社員について、自分の好きな料理以外はどれも同じとみなすので料理ごとに独立に問題を解くことができる。以下、料理 xと好きな料理が xの社員 yについて解く

料理 xが提供される日の集合[tex: \mathcal{D}x]は、 [tex: \mathcal{D}x \triangleq \{ d | d]日目に提供される料理が x\}

 |\mathcal{D}_x| = 0のとき、解は0。以下、そうでない場合を考える。

解がかなり大きくなる可能性があり、また、メニュー xを食べる回数を決めて二分探索するのも難しい。この問題はダブリングを用いて解く。次のようなDPを考える

  •  {\rm dp1}[d_i][k] \triangleq d_i 2^k回後にメニュー xを食べるまでに全てのメニューを食べる回数
  •  {\rm dp2}[d_i][k] \triangleq d_i 2^k回後にメニュー xを食べる日

と定義する。

  •  {\rm dp1}[d_i][0] = \frac{d_{i+1} - d_i - 1}{L} + 1 (ただし d_{i+|\mathcal{D}_x|} = d_i
  •  {\rm dp1}[d_i][k+1] = {\rm dp1}[d_i][k] + {\rm dp1}[next][k]
  •  {\rm dp2}[d_i][k+1] = {\rm dp2}[next][k] \ \ (next = {\rm dp2}[d_i][k])

で更新する。

以下、社員 yについての解を求める。

まず、最初に料理 xを食べる日まで T_yを減らす。 その後、その日から 2^p回食べるまでに全てのメニューを食べる回数が、残り日数を超えないか判定しながら、料理 xを食べる回数をカウントする。

実装

atcoder.jp