Official
B - テープで壁を塗る / Painting a Wall with Tape Editorial by admin
DeepSeek V3概要
複数のマスキングテープが貼られた壁において、少なくとも1本のテープが貼られている部分の合計長さ(区間の和集合の長さ)を求める問題です。
考察
この問題は、N個の区間 \([l_i, l_i + w_i]\) の和集合の長さを求める問題です。素朴なアプローチとして、壁全体を配列で表現して各テープがカバーする範囲をマークする方法が考えられますが、Wが最大 \(10^9\) と非常に大きいため、メモリ制限と計算時間の観点から不可能です。
代わりに、区間を効率的にマージする方法を考える必要があります。区間を開始位置でソートし、隣接する区間が重なるかどうかを確認しながらマージしていくことで、重複を排除した合計長さを計算できます。
アルゴリズム
- すべての区間を開始位置 \(l_i\) でソートします
- 最初の区間を現在のマージ区間として設定します
- ソートされた区間を順に処理します:
- 現在の区間が次の区間と重なる場合(次の区間の開始位置が現在の終了位置以下)、現在の終了位置を拡張します
- 重ならない場合、現在の区間の長さを合計に加算し、次の区間を新しい現在の区間として設定します
- 最後に残っている現在の区間の長さを合計に加算します
このアルゴリズムは区間スケジューリング問題などでよく使われる手法で、重複する区間を効率的にマージできます。
計算量
- 時間計算量: \(O(N \log N)\)(ソートの計算量が支配的)
- 空間計算量: \(O(N)\)(区間を格納するためのメモリ)
実装のポイント
区間の終了位置を比較する際、
max関数を使って現在の終了位置を拡張する必要があります最後の区間を処理した後、マージ中の区間を忘れずに合計に加算することが重要です
入力値が整数であるため、浮動小数点数の精度問題を気にする必要がありません
ソースコード
def main():
import sys
data = sys.stdin.read().split()
if not data:
return
n = int(data[0])
W = int(data[1])
intervals = []
index = 2
for i in range(n):
l = int(data[index])
w = int(data[index+1])
index += 2
intervals.append((l, l + w))
intervals.sort(key=lambda x: x[0])
total = 0
current_start, current_end = intervals[0]
for i in range(1, n):
if intervals[i][0] <= current_end:
current_end = max(current_end, intervals[i][1])
else:
total += current_end - current_start
current_start, current_end = intervals[i]
total += current_end - current_start
print(total)
if __name__ == "__main__":
main()
この解説は deepseekv3 によって生成されました。
posted:
last update: