当前位置:   article > 正文

2024/3/11打卡管道(14届蓝桥杯省赛)——二分+区间合并_蓝桥杯管道c语言做法

蓝桥杯管道c语言做法

目录

题目

思路

代码


题目

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

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

对于位于 L_i 的阀门,它流入的水在 T_i\ \ (T_i\geq S_i)时刻会使得从第 L_i-(T_i-S_i)段到第 L_i+(T_i-S_i) 段的传感器检测到水流。

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

输入格式

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

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

输出格式

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

数据范围

对于 30%30% 的评测用例,n≤200,Si,len≤3000;
对于 70%70% 的评测用例,n≤5000,Si,len≤10^5;
对于所有评测用例,1≤n≤10^5,1≤Si,len≤10^9,1≤Li≤len,Li−1<Li。

输入样例:

  1. 3 10
  2. 1 1
  3. 6 5
  4. 10 2

输出样例:

5

 

思路

        通过题意可以发现,假如说在 t 时刻满足题目要求,那么比 t 大的时刻,管道被覆盖的范围也一定大于等于 t 时刻的,一定满足要求,故具有单调性,此时可以想到用二分来做

如何确定一个时刻 t 所经过的长度是多少?我们通过 L_i  S_i  t 可以来确定一个阀门被打开后所流过的长度。L_i-(T_i-S_i) 即为左边能流到的最远的位置,L_i+(T_i-S_i)即为右边流到最远的位置。

获取到 t 时刻每一个被打开阀门的水流过的区间[\ L_i-(T_i-S_i),\ L_i+(T_i-S_i)\ ]后,如何合并所有的区间,判断是否将管道覆盖完全?此时可以想到区间合并的做法。将所有的区间合并起来,看是否覆盖完管道。

        区间合并:区间合并算法-CSDN博客

代码

注:此题的区间合并并不是两个区间有交集才能合并,例如[1, 2]和[3, 4]也可以进行合并成[1, 4]

注意以为r取到了2e9,再进行区间相加,可能或爆int

  1. // 在 x 的时间内能否完成所有传感器检测到水流
  2. // 在 x 时刻,每个能被打开的阀门被打开后,会有一段区间,那我们合并这段区间,判断是否能从0,覆盖到len
  3. import java.io.*;
  4. import java.util.*;
  5. class Main{
  6. static int N = 100010;
  7. static int n,len;
  8. static int[] l = new int[N]; // 阀门位置
  9. static int[] s = new int[N]; // 阀门打开时间
  10. static Queue<PII> q = new PriorityQueue<>(); // 存储区间,按左端点排序
  11. public static void main(String[] args) throws IOException{
  12. BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
  13. String[] str = in.readLine().split(" ");
  14. n = Integer.parseInt(str[0]);
  15. len = Integer.parseInt(str[1]);
  16. for(int i=1;i<=n;i++){
  17. str = in.readLine().split(" ");
  18. l[i] = Integer.parseInt(str[0]);
  19. s[i] = Integer.parseInt(str[1]);
  20. }
  21. // 进行二分,找最小时间
  22. long l = 0, r = 2000000000; // r需要取到2000000000,因为存在 1 1000000000
  23. // 1000000000 1000000000 这种情况,那么时间就需要1999999999
  24. while(l<r){
  25. long mid = l+r>>1;
  26. if(check(mid)) r = mid; //当前mid时段可以满足
  27. else l = mid+1;
  28. }
  29. System.out.println(r);
  30. }
  31. public static boolean check(long u){
  32. // 获取所有的区间
  33. for(int i=1;i<=n;i++){
  34. long t = u-s[i];
  35. if(t>=0){ // u时间大于等于打开的时间
  36. long x = l[i]-t;
  37. long y = l[i]+t;
  38. q.add(new PII(x,y));
  39. }
  40. }
  41. // 对所有区间进行合并
  42. long st = 0, ed = 0;
  43. while(!q.isEmpty()){
  44. PII i = q.poll();
  45. long x = i.l;
  46. long y = i.r;
  47. if(x<=ed+1){
  48. ed = Math.max(ed,y);
  49. }
  50. else return false;
  51. }
  52. if(ed<len) return false;
  53. else return true;
  54. }
  55. }
  56. class PII implements Comparable<PII>{ // 存储当前时间段被覆盖的区间
  57. long l;
  58. long r;
  59. public PII(long l,long r){
  60. this.l = l;
  61. this.r = r;
  62. }
  63. public int compareTo(PII i){
  64. return this.l-i.l>0?1:-1;
  65. }
  66. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/460882
推荐阅读
相关标签
  

闽ICP备14008679号