公式
B - 荷物の配送センター / Package Distribution Center 解説 by admin
Qwen3-Coder-480B概要
数直線上の荷物を、最も近い配送センターから配送することで、総コストを最小にする問題。
考察
各荷物を「どの配送センターから送るか」を選ぶ問題ですが、コストは単純に「荷物の位置」と「配送センターの位置」の距離 \(|D_i - S_j|\) です。
素朴な方法として、各荷物についてすべての配送センターとの距離を計算し、最小のものを選ぶ方法があります。しかし、これは各荷物に対し \(M\) 回の比較が必要なので、全体で \(O(NM)\) の計算量となり、制約 \(N, M \leq 2 \times 10^5\) では最大で \(4 \times 10^{10}\) 回の計算が必要になり、TLEします。
そこで重要な観察があります:
数直線上では、ある点に最も近い点は、ソートされたリストにおいてその点の前後にあるいずれかである。
つまり、配送センターの座標をソートしておけば、各荷物に対して二分探索により最も近い配送センターを効率的に求めることができます。候補は多くても2つ(挿入位置とその前の要素)なので、計算量を大幅に削減できます。
アルゴリズム
- 配送センターの座標リスト \(S\) をソートする。
- 各荷物の座標 \(D_i\) に対して以下を行う:
bisect.bisect_left(S, D_i)を使い、\(D_i\) の挿入位置posを得る。S[pos]およびS[pos - 1](存在すれば)のうち、より近い方を選んでコストに加える。
- 全荷物のコストを合計したものを出力する。
例
荷物の位置: \(D = [1, 5]\)
配送センターの位置: \(S = [2, 8, 3]\)
- ソートして \(S = [2, 3, 8]\)
- \(D_1 = 1\): 最も近いのは \(S_1 = 2\) → コスト \(|1 - 2| = 1\)
- \(D_2 = 5\): 最も近いのは \(S_2 = 3\) → コスト \(|5 - 3| = 2\)
- 合計コスト: \(1 + 2 = 3\)
計算量
- 時間計算量: \(O((N + M)\log M)\)
- ソートに \(O(M \log M)\)、各荷物に対する二分探索と候補チェックに \(O(N \log M)\)
- 空間計算量: \(O(M)\)
- 配送センターのリストをソートして保持するため
実装のポイント
- 配送センターのリストは事前にソートしておくこと。
bisect.bisect_left()の結果posがリストの端(0またはM)にある場合に、インデックスエラーにならないよう注意。- 各荷物に対して候補は最大2つ(前後の要素)だけ確認すればよい。
## ソースコード
```python
import bisect
import sys
def main():
import sys
input = sys.stdin.read
data = input().split()
N = int(data[0])
M = int(data[1])
D = list(map(int, data[2:2+N]))
S = list(map(int, data[2+N:2+N+M]))
# 配送センターの座標をソート
S.sort()
total_cost = 0
for d in D:
# 二分探索で最も近い配送センターを見つける
pos = bisect.bisect_left(S, d)
min_dist = float('inf')
# 候補は最大2つ(pos-1 と pos)
if pos < M:
min_dist = min(min_dist, abs(d - S[pos]))
if pos > 0:
min_dist = min(min_dist, abs(d - S[pos - 1]))
total_cost += min_dist
print(total_cost)
if __name__ == "__main__":
main()
この解説は qwen3-coder-480b によって生成されました。
投稿日時:
最終更新: