CF1907D 题解

题意:

\(n\) 条线段,初始时在原点。每次可以任意条长度不超过 \(k\) 的一步,但是要满足跳了第 \(i\) 步之后要站在第 \(i\) 条线段上,求最小的 \(k\) 使得可以把所有线段跳完。

题解:

易于发现的,如果已经证明 \(k=x\) 时满足,大于 \(x\) 的一定成立,即答案具有单调性。

考虑二分答案,判断是否合法时,我们维护当前可以跳到的最左的位置和最右的位置,初值为 \(l=r=0\),这样可以维护出下一步的区间,更改时与 \(l,r\) 直接取 \(\max\)\(min\) 即可。

这样判断的复杂度明显 \(O(n)\),所以是 \(O(n\log w)\)

#include<algorithm>
#include<iostream>
const int inf = 1e9;
int t, n, l[200005], r[200005];
inline bool ck(int x){
    int ls = 0, rs = 0;
    for(int i = 1; i <= n; i++){
        ls = std::max(0, ls - x);
        rs = std::min(inf, rs + x);
        if(l[i] > rs || r[i] < ls) return 0;
        ls = std::max(ls, l[i]);
        rs = std::min(rs, r[i]);
    } return 1;
}
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);std::cout.tie(0);
    std::cin >> t;
    while(t--){
        std::cin >> n;
        for(int i = 1; i <= n; i++)
            std::cin >> l[i] >> r[i];
        int ls = 0, rs = inf, as;
        while(ls <= rs){
            int md = ls + rs >> 1;
            if(ck(md)) as = md, rs = md - 1;
            else ls = md + 1;
        }
        std::cout << as << '\n';
    }
}
posted @ 2023-12-11 07:37  xlpg0713  阅读(23)  评论(0)    收藏  举报