公式
D - Maximize the Gap 解説
by
D - Maximize the Gap 解説
by
MMNMM
印刷ページ
まず、答えが \(-1\) かどうかを判定することを考えます。 これは、いわゆる区間スケジューリングの問題になり、次のようなアルゴリズムで解けることが知られています。
- はじめ、選んだ布の列を空列 \(()\) とする。
- すべての布を \(R _ i\) の昇順に並べ、順に以下を行う。
- 最後に選んだ布 \(\lbrack L _ j, R _ j\rbrack\) に対して \(R _ j\lt L _ i\) が成り立つならば、布 \(\lbrack L _ i,R _ i\rbrack\) を選ぶ。
- 選ばれた列の長さが \(K\) 未満なら、答えは \(-1\) 。
スコアが \(x\) 以上であるように布を選べるとき、選んだ布の右端から数直線の正の方向に \(x\) 進むまでに他の選んだ布はありません。 よって、スコアが \(x\) 以上であるように布を選べることは以下と同値です。
任意の正の実数 \(\varepsilon\) に対して、それぞれの布が覆う区間を \(\lbrack L _ i,R _ i+x-\varepsilon\rbrack\) とした問題の答えが \(-1\) でない。
これを利用して二分探索でこの問題を解くことができます。
#include <iostream>
#include <vector>
#include <algorithm>
#include <ranges>
int main() {
using namespace std;
unsigned N, K;
cin >> N >> K;
vector<pair<unsigned, unsigned>> cloth(N);
for (auto&& [L, R] : cloth)
cin >> L >> R;
// 右端でソート
ranges::sort(cloth, {}, [](const auto& p){return p.second;});
// 二分探索で布を伸ばせる限界を見つける
unsigned ans{*ranges::partition_point(views::iota(0U, 1000000000U), [K, &cloth](const unsigned x){
unsigned chosen{}, last{};
// 区間スケジューリングで布をなるべく多く選ぶ
for (const auto& [L, R] : cloth) {
if (last <= L) {
++chosen;
last = R + x + 1; // 右に x だけ伸ばしておく
}
}
// K 枚以上選べたら OK
return chosen >= K;
})};
// 1 以上伸ばせるなら
if (ans) {
cout << ans << endl; // それが答え
} else { // 伸ばせないなら
cout << -1 << endl; // -1
}
return 0;
}
投稿日時:
最終更新:
