Acwing5407管道

题目

有一根长度为 len 的横向的管道,该管道按照单位长度分为 len 段,每一段的中央有一个可开关的阀门和一个检测水流的传感器。

一开始管道是空的,位于 Li 的阀门会在 Si 时刻打开,并不断让水流入管道。

对于位于 Li 的阀门,它流入的水在 Ti(Ti≥Si)时刻会使得从第 Li−(Ti−Si) 段到第 Li+(Ti−Si)段的传感器检测到水流。

求管道中每一段中间的传感器都检测到有水流的最早时间。

输入格式

输入的第一行包含两个整数 n,len用一个空格分隔,分别表示会打开的阀门数和管道长度。

接下来 n 行每行包含两个整数 Li,Si,用一个空格分隔,表示位于第 Li 段管道中央的阀门会在 Si 时刻打开。

输出格式

输出一行包含一个整数表示答案。

数据范围

对于 30%的评测用例,n≤200,Si,len≤3000

对于 70% 的评测用例,n≤5000,Si,len≤105

对于所有评测用例,1≤n≤105,1≤Si,len≤109,1≤Li≤len1,Li−1<Li

输入样例:

3 10
1 1
6 5
10 2

输出样例:

5

代码与思路

java 复制代码
import java.util.*;

public class Main {
    static class Pair implements Comparable<Pair> {
        int x, y;

        public Pair(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public int compareTo(Pair o) {
            return Integer.compare(this.x, o.x);
        }
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();  // 事件数量
        int m = in.nextInt();  // 区间右端点

        Pair[] w = new Pair[n];  // 事件数组
        for (int i = 0; i < n; i++) {
            int L = in.nextInt();  // 事件左端点
            int S = in.nextInt();  // 事件发生时间
            w[i] = new Pair(L, S);  // 构建事件 Pair 对象并加入数组
        }

        // 调用二分查找方法,找到满足条件的最小时间点
        int ans = binarySearch(w, m);
        System.out.println(ans);
    }

    // 检查是否存在一个时间点 mid,使得所有事件在该时间点前结束
    static boolean check(Pair[] w, int m, int mid) {
        List<Pair> q = new ArrayList<>();  // 存储事件在时间点 mid 时的区间范围
        for (int i = 0; i < w.length; i++) {
            int L = w[i].x;  // 事件 i 的左端点位置
            int S = w[i].y;  // 事件 i 的发生时间
            if (S <= mid) {  // 如果事件 i 在当前时间 mid 之前结束
                int t = mid - S;  // 计算事件 i 的持续时间
                int l = Math.max(1, L - t);  // 计算事件 i 在当前时间 mid 的左端点位置
                int r = Math.min(m, L + t);  // 计算事件 i 在当前时间 mid 的右端点位置
                q.add(new Pair(l, r));  // 将事件 i 的区间范围加入到列表中
            }
        }
        Collections.sort(q);  // 将事件按左端点位置进行排序

        int st = -1, ed = -1;  // 初始化起始和结束端点
        // 遍历事件列表,合并区间并更新起始和结束端点
        for (Pair p : q) {
            if (p.x <= ed + 1) {
                ed = Math.max(ed, p.y);  // 合并区间
            } else {
                st = p.x;
                ed = p.y;
            }
        }

        return st == 1 && ed == m;  // 检查是否覆盖了整个区间 [1, m]
    }

    // 二分查找满足条件的最小时间点
    static int binarySearch(Pair[] w, int m) {
        int l = 0, r = (int) 2e9;  // 初始化二分查找的左右边界
        while (l < r) {
            int mid = l + (r - l) / 2;  // 计算中间时间点
            if (check(w, m, mid)) {  // 如果当前时间点满足条件
                r = mid;  // 缩小右边界
            } else {
                l = mid + 1;  // 否则,增大左边界
            }
        }
        return r;  // 返回最小满足条件的时间点
    }
}
相关推荐
代码小鑫2 小时前
A035-基于Spring Boot的企业内管信息化系统
java·开发语言·spring boot·后端·spring
Spy972 小时前
django 过滤器的执行
后端·python·django
camellias_7 小时前
SpringBoot(二十三)SpringBoot集成JWT
java·spring boot·后端
tebukaopu1487 小时前
springboot如何获取控制层get和Post入参
java·spring boot·后端
昔我往昔7 小时前
SpringBoot 创建对象常见的几种方式
java·spring boot·后端
灭掉c与java7 小时前
第三章springboot数据访问
java·spring boot·后端
啊松同学7 小时前
【Java】设计模式——工厂模式
java·后端·设计模式
枫叶_v8 小时前
【SpringBoot】20 同步调用、异步调用、异步回调
java·spring boot·后端
源码12159 小时前
ASP.NET MVC宠物商城系统
后端·asp.net·宠物
Ai 编码助手10 小时前
Go语言 实现将中文转化为拼音
开发语言·后端·golang