蓝桥杯 b组《管道》解法

324 阅读3分钟

作者最近在做蓝桥杯真题,在这里写一些个人见解,虽然掌握了一些算法,但是具体实际运用起来不是很行,没有头绪,所以在这里将自己的做题思路整理出来。望大佬指点一二。

这是2023年蓝桥杯省赛b组的一道题,本人是Python组的,下面是题目:

image.png

image.png

题目意思:

就是有一个管道,水流流入(无论哪一端),长度是len,分为len段,每段有一个阀门和传感器,每一段打开的时间都是不同的,可能中间的某一段会在k时刻打开,末尾会在m时刻打开,可能k>m,公式Li-Ti+Si和Li+Ti-Si。这个可以理解为一个区间,闭区间。求时间的问题。

解法思路:

  1. 在评测用例规模的地方,有个len<10的9次方,1个亿的数据量长度,这个在python组的话,循环时间必定很长,普通的循环显然是不太合理
  2. 这个就可能让我们想道二分,但具体二分什么呢,在上面说了区间这个东西,就是水流流过阀门,传感器检测到水流的这个距离,是个区间,题目要求让每一个段都检测到水流,那也就是说这个区间(所有的区间是联通起来的),可以合并到一起,左端点小于等于1(为什么是1呢,可以看最后的测评用例,最少有一个段,且长度最小为1),右端点大于等于len、
  3. 既然区间需要合并,那需要什么东西呢,题目中的公式里面的Ti是个未知数,题目让我们去求这个Ti,Si的最大值是1个亿,最小是1,那我们的Ti的最小值就是1,最大值就是10e9。
  4. 知道了这个Ti的范围,可以知道10e9的数据量很大,在Python里面普通的循环一亿次肯定是大于运行时间限制的12s的,一亿次得好几十分钟吧,还记得前面说到的二分嘛,二分就快捷很多
  5. 可以了解到这个二分,就是让我们去二分这个Ti。这下就不难理解了,这个题考察的就是一个二分加区间合并的算法思想。

通过代码

def check(x):
  nk = []
  for i in range(n):
    if arr[i][1]<=x:
      nk.append([arr[i][0]-x+arr[i][1],arr[i][0]+x-arr[i][1]])
  nk.sort(key = lambda x:x[0])
  if nk == []:
    return False
  r = nk[0][1]
  if nk:
    for i in range(1,len(nk)):
      if nk[i][0]<=r+1:
        r = max(nk[i][1],r)
        # print()
      else:
        return False
  if r>=m and nk[0][0]<=1:
    return True
  return False
l,length = 0,10**9
n,m = map(int,input().split())
arr = []
for i in range(n):
  arr.append(list(map(int,input().split())))
while l<length:
  mid = l+length >> 1
  if check(mid):
    length = mid
  else:
    l = mid + 1
print(length)

代码写的不是很完美,欢迎大佬拷打。

check函数用来检测二分出来的Ti是否符合题目要求的Ti,在区间合并前一定要进行排序(对区间左端点排序),7行后面可以对左端点进行判断一下,提前返回。不得不说py在做蓝桥杯这些算法题的时候真的很慢。大佬很可以发一下c++的代码,让俺来学习学习