Please sign in first.
Official
C - 中継局の設置 / Installation of Relay Stations Editorial
by
C - 中継局の設置 / Installation of Relay Stations Editorial
by
physics0523
まず、中継局を \(3\) つ以上設置する意味はありません。そのうち座標が最も小さい \(1\) つを排除することで合計のコストを下げることができます。
以降、座標の差が \(D\) 以内の中継局を \(2\) つ採用し、コストの合計を最小化するという問題を解きます。
尺取り法 によってデータ構造を操作する方針が最も楽でしょう。
- 多重集合 \(ms\) を用意する。
- まず、中継局の候補を座標の昇順にソートする。
- \(l=1,2,\dots,N\) について、以下を繰り返す。
- 左から \(l\) 番目にある中継局の候補の座標を \(x\) としたとき、座標 \(x+D\) 以下の中継局の候補をすべて \(ms\) に追加する。
- \(ms\) のうち小さい方から \(2\) つの和が、解の候補となる。
- 左から \(l\) 番目の中継局を排除する。
中継局の候補を適切に \(ms\) に追加することで、追加と削除を全ての中継局についてそれぞれ \(1\) 回に抑えることができます。
「任意の要素を \(1\) つ追加する」「任意の要素を \(1\) つ削除する」「小さい方から \(2\) つの和を求める」が簡単に実行できるデータ構造はいくつかありますが、 C++ では multiset を使うと実装が楽になります。詳細は実装例を参考にしてください。
本解法の時間計算量は \(O(N \log N)\) です。
実装例 (C++):
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
using pl=pair<ll,ll>;
int main(){
ll N,D;
cin >> N >> D;
vector<pl> vp(N);
for(auto &nx : vp){
cin >> nx.first >> nx.second;
}
sort(vp.begin(),vp.end());
ll res=8e18,r=0;
multiset<ll> ms;
for(ll l=0;l<N;l++){
while(r<N && vp[r].first-vp[l].first<=D){
ms.insert(vp[r].second);
r++;
}
if(ms.size()>=2){
auto it=ms.begin();
ll v=(*it);
it++;
res=min(res,v+(*it));
}
ms.erase(ms.find(vp[l].second));
}
if(res>4e18){res=-1;}
cout << res << "\n";
return 0;
}
posted:
last update:
