当前位置: 首页 > article >正文

管道(acwing,蓝桥杯,二分)

题目描述:

有一根长度为 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≤1e5;
对于所有评测用例,1≤n≤1e5,1≤Si,len≤1e9,1≤Li≤len,Li−1<Li。

输入样例:

3 10
1 1
6 5
10 2

输出样例:

5

分析步骤:

  第一:我们拿到这道题我们可以看到,是一段管道里有许多的水龙头,当开启不同水龙头的时候它可以向两边扩散速度是:1段/s。不同水龙头控制的区域也不一样,至此我们分析出了第一个特点有区间问题,需要合并看看有没有全部覆盖管道

            我们还可以发现当时间开的越长,管道内有水的区域也越长,这呈现一种单调的特点,并且我们可以求出一个时间点,在这个时间点的左边管道内不能全部都流过水,在这个时间点和以后都可以覆盖全管道。至此也满足了二分的特点

            所以本题要运用二分+区间合并来做;

 

第二:知道了考的知识点,咱们就要书写主函数,把握整体框架。

           首先把值都输入进去,其次开始二分

            定义我们的左节点 l 为 0 因为有可能水管从第零分钟就一直开着,并且每个管道段落都有水龙头,所以最小时间可能是 0

             定义右节点 r 为 2e9 .因为题目说了 Si 最大为 1e9  所以有可能在最后一秒也就是1e9秒时 ,开启开关并且只有一个开关且在第一个管道之内,所以要覆盖管道又要1e9s 所以两个 1e9 相加就是 2e9。

           求出mid,再判断一下这个 mid 的值

            如果是对的,则证明比 mid 的时间大小更大的值就更可以覆盖满管道.因为假如 mid 为5秒时已经覆盖了管道,那么6秒更会是管道内充水。所以应该将 mid 赋值给 r

            如果 mid 的时间大小不可以,那么比mid还小的话更是不可能覆盖的了管道了。所以应该将 mid + 1 的值 赋值给 l;

int main()
{
    cin>>n>>m;
    for(int i = 0 ; i < n ; i ++){
        cin>>q[i].x>>q[i].y;
    }
    LL l = 0 , r = 2e9;
    while(l<r){
        LL mid = (l+r) / 2;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    cout<<r;
    return 0;
}

  第三:书写 check 函数定义一个 计数器 cnt 用一个f or 循环将之前存储的数据取出来,如果mid这个时间大于了我们的S这个时间的话,那么就意味着这个开关已经开启了并且流出了一段的水,这段时间的差值 就是这个开关向左右两边扩散的距离,所以我们用 t 计算出这段时间差。

          确定左右区间:

           我们接下来看这个开关可以控制的区间范围因为 t 就是扩散的距离 所以我们的 int l = max(1, L-t ) ,左边界范围就是第 L 个开关向左走了 t 时间的路 和 1 取最大值进行动态更新

            r = min((LL)m,(LL)L+t);右边界范围就是第 L 个开关向左走了 t 时间的路 和 m 取最小值进行动态更新因为不可以超过管道长度。

            最后将这个开关的区间边界放入 p 数组之中;至此我们区间范围已然确定。

int cnt = 0 ; 
     for(int i = 0 ; i < n ; i ++){
         int L = q[i].x , S = q[i].y;
         if(mid >= S){
             int t = mid - S;
             int l = max(1,L-t) , r = min((LL)m,(LL)L+t);
                  p[cnt++]={l,r};
         }
     }

  第四:接下来进行区间合并。我们先进行sort排序这样这些区间的左端点就可以从小到大排序,我们就只要比较右端点就行。

           我们定义左端点 st 为 -1 ; 右端点ed 为 -1 

           如果 我们的左端点st <= 上一个存值的区间右端点 加 1 的话我们就只需要更新一下我们右节点 ed 就可以把两个区间合并了。为什么要加1?直接小于等于 ed 不行吗? 不可以 。因为ed那里已经有水了,只是 ed+1 的那个点没有水,所以如果我们的 l == ed+1的话也是可以算连接上了的。

          如果 我们的左端点st > 上一个存值的区间右端点 加 1 的话 就证明这两个区间必有间隙则更改我们的st 和 ed为新的区间端点。

         最终返回判断一下st是否为 1 并且 ed是否为管道长度。如果都符合就返回true,有一个不符合就是false;

            


     sort(p,p+cnt);
     int ed = -1 , st = -1;
     for(int i = 0 ; i < cnt ; i ++){
        if(p[i].x <= ed + 1 ) ed = max(ed , p[i].y);
        else st = p[i].x , ed = p[i].y;
     }
    return st == 1 and ed == m;

  

注意:区间合并就三种情况相交里包含两种,还有一种相离

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#define x first
#define y second

using namespace std;

const int N = 1e5+10;
typedef long long LL;
typedef pair<int, int> PII;
PII q[N], p[N];
LL n,m;

bool check(int mid){
     int cnt = 0 ; 
     for(int i = 0 ; i < n ; i ++){
         int L = q[i].x , S = q[i].y;
         if(mid >= S){
             int t = mid - S;
             int l = max(1,L-t) , r = min((LL)m,(LL)L+t);
                  p[cnt++]={l,r};
         }
     }
     sort(p,p+cnt);
     int ed = -1 , st = -1;
     for(int i = 0 ; i < cnt ; i ++){
        if(p[i].x <= ed + 1 ) ed = max(ed , p[i].y);
        else st = p[i].x , ed = p[i].y;
     }
    return st == 1 and ed == m;
}

int main()
{
    cin>>n>>m;
    for(int i = 0 ; i < n ; i ++){
        cin>>q[i].x>>q[i].y;
    }
    LL l = 0 , r = 2e9;
    while(l<r){
        LL mid = (l+r) / 2;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    cout<<r;
    return 0;
}

 


http://www.kler.cn/a/274439.html

相关文章:

  • APM32F411使用IIS外设驱动es8388实现自录自播
  • Pytorch | 从零构建ResNet对CIFAR10进行分类
  • 面试小札:Java后端闪电五连鞭_8
  • 免费GIS工具箱:轻松将glb文件转换成3DTiles文件
  • 【AIGC-ChatGPT进阶副业提示词】末日生存指南 2.0:疯狂科学家的荒诞智慧
  • RabbitMQ 路由(Routing)通讯方式详解
  • P8717 [蓝桥杯 2020 省 AB2] 成绩分析 Python
  • 【洛谷 P9242】[蓝桥杯 2023 省 B] 接龙数列 题解(线性DP)
  • WRF模型运行教程(ububtu系统)--III.运行WRF模型(官网案例)
  • 我的尝试:Codigger + Vim
  • 迷宫问题(c++题解)
  • MQTT建立连接
  • 【C++】每日一题 219 最小栈
  • Leetcode 79. 单词搜索
  • 【进阶五】Python实现SDVRP(需求拆分)常见求解算法——自适应大邻域算法(ALNS)
  • 学习vue3第六节(vue3 中 computed watch watchEffect)
  • 有什么小程序适合个人开发?
  • Aigtek超声功率放大器产品介绍
  • 力扣1. 两数之和
  • 腾讯云服务器多少钱1个月?2024一个月收费阿济格IE吧
  • 数据结构:详解【顺序表】的实现
  • PlantUML Integration 编写短信服务类图
  • 深入挖掘C语言之——枚举
  • Redis数据结构对象中的对象共享、对象的空转时长
  • 【Godot4.2】2D导航01 - AStar2D及其使用方法
  • python企业编码管理的程序(附源码)