問題はこちら
問題概要
解説
つのオーブンだと,料理を
つのグループ
に分けた時の
がかかる時間となる.以降どのように料理を
つのグループに分けるかが問題となる.
通り試していたら時間がかかるので別の方法を考える.
を
の総和(
)とおく.
を決めると
が決まるので
となるから,
を最小にする
はどのようなものかを考える.
ここで,とする(
のときは,
と
を入れ替えることで
となる).このとき,かかる時間は
であり,これを小さくするには
を大きくする必要がある.
を変形すると
となるので,
個の料理をいくつか選んでできる
の総和のうち
以下の最大値が答えになる.これはナップサック問題とか部分和問題のようにDPで解ける.
ナップサック問題とか部分和問題を知らない人はEDPCとかで練習してください.
おまけ
慣れてないとおまけ2
途中で最大値の最小化みたいな話が出てきますが,よく「最大値の最小化は二分探索!」と言われているので二分探索を考えてしまうかもしれません.ここで,なぜ最大値の最小化を二分探索により解くことができる問題があるかを説明します.最大値の最小化はのような形になり,
のような部分は扱うのが難しいことがあります.ここで,
であることと,任意の
に対して
であることは同値なので,
を決めうつことで
という
がたがいに関係し合う式から,
という各
について独立に考えることができる式に変換できます.さらに,「
に対して
であるか」の真偽は単調であるので二分探索が可能になります.
今回の問題では,です.
を決めたとき,
や
は元の問題より簡単に求まるわけではなさそうなので二分探索で解くのは微妙です(解けないことはないが意味ない).
二分探索で解けるかな?と思うことは悪いことではないですが,このように考えることですぐに無理そうだな(意味ないな)と思うことができます.
例題:https://yukicoder.me/problems/no/710
提出プログラム
pythonのプログラムです.import numpy as np N = int(input()) T = list(map(int, input().split())) S = np.sum(T) DP = np.zeros(S//2+1,dtype=np.bool) DP[-1] = 1 for i in range(N): if S//2+1-T[i] < 0: continue DP[:S//2+1-T[i]] |= DP[T[i]:] #numpyを用いていっぺんに遷移 print(S-S//2+np.argmax(DP))