D - Wi-Fiスポットの接続 / Wi-Fi Spot Connection Editorial by admin
Qwen3-Coder-480B概要
数直線上の区間をカバーするWi-Fiルーターがあり、始点 \(0\) から終点 \(L\) まで移動する際に、常に少なくとも1つのルーターの電波圏内を保ちながら移動可能かどうかを判定する問題。
考察
この問題では、それぞれのWi-Fiルーターがカバーする区間 \([X_i - R_i, X_i + R_i]\) が与えられ、これらの区間によって数直線の一部が覆われています。高橋君は、連続的にカバーされた領域を渡って移動しなければならないため、区間の「隙間」があると到達できません。
素朴なアプローチとその問題
例えば、すべての区間を愚直にマージして、最終的に \([0, L]\) が完全に含まれるか調べる方法があります。しかし、区間が多い場合(最大 \(2 \times 10^5\))、無駄が多く時間がかかります。
また、区間の端点が非常に大きい(最大 \(10^9\))ため、区間をビットなどで管理することも不可能です。
解決策:貪欲法による区間スケジューリング
この問題は典型的な区間スケジューリング問題の亜種と考えることができます。区間をソートして、今カバーしている範囲の終端を最大限伸ばせる区間を選ぶ戦略が有効です。
具体的には、以下のように進めます:
1. 各ルーターのカバー範囲を区間 \([l_i, r_i]\) として計算し、開始位置 \(l_i\) で昇順にソート。
2. 最初に、区間の開始が \(0\) 以降になっていないか確認(\(0\) がカバーされていなければ即 No)。
3. 現在カバーしている範囲の終端 current_end を管理しながら、その中からさらに伸ばせる最も遠い終端を持つ区間を選んでいく。
4. current_end が \(L\) 以上になったら成功。
このように、「次の選択肢の中で、最も遠くまでカバーできるものを使う」という貪欲法により、最適解が得られます。
アルゴリズム
- 各ルーターのカバー範囲 \([X_i - R_i, X_i + R_i]\) を計算し、\((開始位置, 終了位置)\) のペアとしてリストに格納。
- 開始位置の昇順で区間をソート。
- 最初の区間が \(0\) を含まない場合、
Noを出力。 current_end = 0とし、左から区間を見ていく:- 現在の区間の開始位置が
current_endよりも大きい場合 → 隙間があるためNo。 - そうでない限り、開始位置が
current_end以下の区間の中から、最も遠い終了位置を持つものを選び、current_endを更新。
- 現在の区間の開始位置が
current_end >= Lになった時点でYesを出力。- 全区間を見た後でも到達できていなければ
No。
例
入力例:
3 10
2 3
5 2
8 3
区間は: - \([2-3, 2+3] = [-1, 5]\) - \([5-2, 5+2] = [3, 7]\) - \([8-3, 8+3] = [5, 11]\)
これらを開始位置でソートすると: - \([-1, 5]\) - \([3, 7]\) - \([5, 11]\)
処理の流れ:
1. current_end = 0。最初の区間 \([-1, 5]\) で更新 → current_end = 5
2. 次の区間 \([3, 7]\) は使用可能 → current_end = 7
3. 次の区間 \([5, 11]\) も使用可能 → current_end = 11
4. 11 >= 10 なので Yes
計算量
- 時間計算量: \(O(N \log N)\) (ソートが支配的)
- 空間計算量: \(O(N)\) (区間を保存するリスト)
実装のポイント
- 区間を \((開始位置, 終了位置)\) として前処理し、開始位置でソートするのが重要。
current_endを使いながら、どの区間までカバーできるかを逐次更新。- 最初の区間が \(0\) をカバーしていない場合や、途中でギャップがある場合はすぐに
Noを出力。 - 高速な入力処理(
sys.stdin.readなど)が必要(特にPythonでは推奨)。
## ソースコード
```python
import sys
input = sys.stdin.read
def main():
data = input().split()
N = int(data[0])
L = int(data[1])
routers = []
index = 2
for _ in range(N):
x = int(data[index])
r = int(data[index+1])
routers.append((x - r, x + r))
index += 2
# 区間を開始位置でソート
routers.sort()
# 座標0をカバーする区間があるか確認
if not routers or routers[0][0] > 0:
print("No")
return
current_end = 0
i = 0
while i < N:
# 現在カバーしている範囲から次に伸ばせる最も遠い範囲を探す
if routers[i][0] > current_end:
# ギャップがある場合到達不可
print("No")
return
max_reach = current_end
while i < N and routers[i][0] <= current_end:
max_reach = max(max_reach, routers[i][1])
i += 1
current_end = max_reach
if current_end >= L:
print("Yes")
return
# 最後に到達できなかった場合
print("No")
if __name__ == "__main__":
main()
この解説は qwen3-coder-480b によって生成されました。
posted:
last update: