B - 畑の収穫 / Harvest from the Field Editorial by admin
gemini-3.5-flash-thinking概要
すべての畑を収穫可能にするために必要な作業量の総和を求め、1日あたりに作業員全員がこなせる作業量 \(M\) から、必要な最小日数を計算する問題です。
考察
一見すると「どの日にどの畑に何人の作業員を割り当てるか」という複雑なスケジュールを立てる必要があるように見えますが、問題の条件を整理すると非常にシンプルに考えることができます。
必要な総作業量 すべての畑 \(i\) を収穫可能にするためには、畑 \(i\) に少なくとも \(D_i\) の作業量を割り当てる必要があります。したがって、農場全体で必要な総作業量は、各畑の必要作業量の総和 \(S = \sum_{i=1}^N D_i\) となります。
1日あたりの作業量 作業員は \(M\) 人おり、全員を必ずいずれかの畑に割り当てる必要があります。また、1人が1日にこなす作業量は \(1\) なので、農場全体では毎日ちょうど \(M\) の作業量が発生します。
日数の下限 必要な日数を \(X\) 日とすると、 \(X\) 日間でこなせる作業量の合計は \(X \times M\) となります。これが全体の必要作業量 \(S\) 以上でなければならないため、以下の不等式が成り立ちます。 $\(X \times M \geq S \implies X \geq \frac{S}{M}\)\( 日数 \)X\( は整数であるため、必要な最小日数は \)\frac{S}{M}\( を切り上げた値、すなわち \)\lceil \frac{S}{M} \rceil$ 日となります。
この下限が常に達成可能である理由 問題文より、以下の柔軟なルールが認められています。
- 1つの畑に何人でも(最大 \(M\) 人まで)同時に割り当ててよい。
- すでに収穫可能になった畑にさらに作業員を割り当ててもよい(余剰な作業が発生してもよい)。
- 日ごとに割り当てを自由に変えてよい。
このため、例えば「畑1に \(D_1\)、畑2に \(D_2\)、……と順番に作業量を割り当てていき、1日の上限 \(M\) を超えた分は翌日に回す」というように貪欲に割り振ることで、途中で作業が無駄になることなく、総作業量 \(S\) を \(X\) 日間で過不足なく分配することができます。
したがって、個々の \(D_i\) の値に細かくこだわる必要はなく、「総作業量 \(S\) を、1日あたり \(M\) ずつ進めたときに何日かかるか」を計算するだけで正解を導くことができます。
アルゴリズム
- 与えられた \(D_1, D_2, \ldots, D_N\) の総和 \(S\) を計算します。
- 最小日数 \(X = \lceil S / M \rceil\) を計算します。
- 整数型のみで切り上げ除算を行うため、多くのプログラミング言語では
(S + M - 1) // Mという式を用いて計算します。
- 整数型のみで切り上げ除算を行うため、多くのプログラミング言語では
- 計算した \(X\) を出力します。
計算量
- 時間計算量: \(O(N)\) \(D_i\) の総和を求めるために、入力された配列を1回走査する時間がボトルネックとなります。\(N \leq 10^6\) であるため、十分高速に動作します。
- 空間計算量: \(O(N)\) 入力をすべて配列として保持するために \(O(N)\) のメモリを使用します。
実装のポイント
オーバーフローへの注意 \(N \leq 10^6\)、 \(D_i \leq 10^9\) であるため、総和 \(S\) は最大で \(10^{15}\) に達します。C++ などの 32bit 整数型(
int)を使用する言語ではオーバーフローが発生するため、必ず 64bit 整数型(long longなど)を使用してください(Pythonでは自動的に多倍長整数として扱われるため心配ありません)。高速な入出力 \(N\) の値が大きいため、Pythonでは
sys.stdin.readを用いて入力を一括で取得することで、実行時間を大幅に短縮できます。ソースコード
import sys
def main():
# 入力を高速に読み込む
input_data = sys.stdin.read().split()
if not input_data:
return
N = int(input_data[0])
M = int(input_data[1])
# D_i の総和を計算
total_D = sum(map(int, input_data[2:]))
# 最小日数を計算
ans = (total_D + M - 1) // M
print(ans)
if __name__ == '__main__':
main()
この解説は gemini-3.5-flash-thinking によって生成されました。
posted:
last update: