当前位置:   article > 正文

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

管道(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。

输入样例:

  1. 3 10
  2. 1 1
  3. 6 5
  4. 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;

  1. int main()
  2. {
  3. cin>>n>>m;
  4. for(int i = 0 ; i < n ; i ++){
  5. cin>>q[i].x>>q[i].y;
  6. }
  7. LL l = 0 , r = 2e9;
  8. while(l<r){
  9. LL mid = (l+r) / 2;
  10. if(check(mid)) r = mid;
  11. else l = mid + 1;
  12. }
  13. cout<<r;
  14. return 0;
  15. }

  第三:书写 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 数组之中;至此我们区间范围已然确定。

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

  第四:接下来进行区间合并。我们先进行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;

            

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

  

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

代码:

  1. #include <iostream>
  2. #include <cstring>
  3. #include <algorithm>
  4. #define x first
  5. #define y second
  6. using namespace std;
  7. const int N = 1e5+10;
  8. typedef long long LL;
  9. typedef pair<int, int> PII;
  10. PII q[N], p[N];
  11. LL n,m;
  12. bool check(int mid){
  13. int cnt = 0 ;
  14. for(int i = 0 ; i < n ; i ++){
  15. int L = q[i].x , S = q[i].y;
  16. if(mid >= S){
  17. int t = mid - S;
  18. int l = max(1,L-t) , r = min((LL)m,(LL)L+t);
  19. p[cnt++]={l,r};
  20. }
  21. }
  22. sort(p,p+cnt);
  23. int ed = -1 , st = -1;
  24. for(int i = 0 ; i < cnt ; i ++){
  25. if(p[i].x <= ed + 1 ) ed = max(ed , p[i].y);
  26. else st = p[i].x , ed = p[i].y;
  27. }
  28. return st == 1 and ed == m;
  29. }
  30. int main()
  31. {
  32. cin>>n>>m;
  33. for(int i = 0 ; i < n ; i ++){
  34. cin>>q[i].x>>q[i].y;
  35. }
  36. LL l = 0 , r = 2e9;
  37. while(l<r){
  38. LL mid = (l+r) / 2;
  39. if(check(mid)) r = mid;
  40. else l = mid + 1;
  41. }
  42. cout<<r;
  43. return 0;
  44. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/267549?site
推荐阅读
相关标签
  

闽ICP备14008679号