ツバサの備忘録

主に備忘録代わりに精進記録を載せていくつもりです。

JOI2017/2018 予選 D - 水ようかん (Mizuyokan)

問題
提出コード

解法

  • dp[i][j] = i番目までのようかんを切り終えて、ピースの最小値がjになるように切り分けたときに取り得る"ピースの最大値"の最小値

とします。こうすることで、答えはmin(dp[n][j] - j)で求めることができます。
すると、[k,i]でピースを作成すると仮定した際に遷移がどうなるかを考えればよいため、S_{l,r} = \sum_{i = l}^{r}L_{i}として、
dp[i][j]  = min(max(dp[k-1][j],S_{k,i})) (ただし j \leqq S_{k,i} を満たす)
と考えたくなります。初期値はdp[i][S_{1,i}] = S_{1,i}です。
しかし、このままではおそらくACすることはできません(参考)

以下のようなケースを考えます。

2
10
1

これは、サンプル2のようかんを左右反転させただけなので、明らかに答えは9です。
しかし、上のままの解法だと、おそらく答えが合わないかと思います。
この原因は、上のDP解が左端のようかんが最小値になる場合のみについて考えていることによるものです。
このケースのように、右端が最小のピースになったり、3つ以上に切り分けたうちの真ん中が最小になるケースも存在します。
これを解消するために、DPの定義を少し書き換えます。

  • dp[i][j] = 最後まで切り分けた結果、ピースの最小値がj以上になると仮定したときの、i番目までのようかんを切り終えたときに取り得る"ピースの最大値"の最小値

すると、遷移はそのまま、初期値はdp[0][j] = 0とすることで、このDPを計算できます。
答えも最初と同様min(dp[n][j] - j)で求めることができます。が、仮定と矛盾する場合、つまりピースの最小値がj以上となる切り分け方が存在しなかった場合は排除しなければなりません。この場合は、dp[n][j] = S_{1,n}になっているため、容易に場合分けをして排除することができます。
切り分け方は存在するが、ピースの最小値がjぴったりにならないものも存在します。が、今回はj以上、という仮定を置いているので、jぴったりにならない場合は、j+1以降のどこかでぴったりになるはずです。dp[n][j] - jは、jが大きい方が値が小さくなるので、min(dp[n][j] - j)によって問題なく最小値を取り出すことができます。