我的编程空间,编程开发者的网络收藏夹
学习永远不晚

第十四届蓝桥杯省赛 Python B 组 D 题——管道(AC)

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

第十四届蓝桥杯省赛 Python B 组 D 题——管道(AC)

目录

1. 管道

1. 问题描述

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

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

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

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

2. 输入格式

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

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

3. 输出格式

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

4. 样例输入

3 101 16 510 2

5. 样例输出

5

6. 评测用例规模与约定

对于 30 30 30% 的评测用例, n ≤ 200 n \leq 200 n200 Si , len ≤ 3000 S_i, \text{len} \leq 3000 Si,len3000

对于 70 70 70% 的评测用例, n ≤ 5000 n \leq 5000 n5000 Si , len ≤ 1 05 S_i, \text{len} \leq 10^5 Si,len105

对于所有评测用例, 1 ≤ n ≤ 1 05 ​ 1 \leq n \leq 10^5​ 1n105 1 ≤ Si , len ≤ 1 09 ​ 1 \leq S_i,\text{len} \leq 10^9​ 1Si,len109 1 ≤ Li ≤ len​ 1 \leq L_i \leq \text{len}​ 1Lilen L i − 1 < Li ​ L_{i-1} < L_i​ Li1<Li

2. 解题思路

对于一个时间点 x x x,如果此时所有传感器都能检测到水流,那么当时间点大于 x x x 时也一定保证所有传感器都能检测到水流。题目要求我们找到满足条件的最小时间点,因为答案具有二段性,所以我们可以想到二分答案。

有了二分的思路后,问题转换为对于一个确定的时间点 x x x,我们如何判断此时所有传感器都能检测到水流?仔细思考,当时间确定后,对于一个位于 ai a_i ai 且开启时间为 Si ( Si ≤ x ) S_i(S_i \leq x) Si(Six) 的阀门,它的水流实际就是一条覆盖区间 [ ai − ( x − Si ) , ai + ( x − Si ) ] [a_i-(x-S_i),a_i+(x-S_i)] [ai(xSi),ai+(xSi)] 的线段。

我们可以将所有 Si ≤ x S_i \leq x Six 的阀门都进行转换,实际上得到的就是若干条线段。判断所有传感器是否都能检测到水流,等价于判断能否用这若干条线段覆盖区间 [ 1 , len ] [1,\text{len}] [1,len],问题接着转换为区间覆盖问题。

区间覆盖是一个经典问题。我们可以按区间的左端点来排序这些区间。接下来,我们检查这些区间是否覆盖了整个管道。如果第一个区间的左端点大于 1 1 1,那么表示管道的开始部分没有被覆盖,直接返回 false。否则我们设一个变量 r r r 表示可到达的最远距离, r r r 的初始值为第一个区间的右端点。我们接着检查其他区间是否与 r r r 相邻或重叠。如果当前区间和 r r r 相邻或重叠,我们将当前区间的右端点和 r r r 取最大值。最后如果 r ≥ len r \geq \text{len} rlen 则说明成功覆盖所有区间,否则说明没有。

回过头来考虑如何书写二分,设 l l l 为答案的下界, r r r 为答案的上界,如果二分得到的时间点 mid \text{mid} mid 符合条件,因为大于 mid \text{mid} mid 的时间点也一定符合条件,所以更新 r = mid r=\text{mid} r=mid,否则更新 l = mid+1 l=\text{mid+1} l=mid+1。我们重复这个过程,直到搜索范围的左右端点相等,此时就找到了最早的时间。 当然 l , r l,r l,r 的初始值我们也需要思考, l l l 显然为 1 1 1,而 r r r 我们需要考虑极限情况,即只存在一个最左或最右的阀门在最晚的时间点打开,显然此时需要的时间为 2 × 1 09 2 \times 10^9 2×109,所以 r r r 的初始值为 2 × 1 09 2 \times 10^9 2×109

时间复杂度: O ( n log ⁡ n2 ) O(n\log n^2) O(nlogn2)

3. AC_Code

  • C++
#includeusing namespace std;typedef long long LL;#define sz(s) ((int)s.size())int n, m;int main(){ios_base :: sync_with_stdio(false);cin.tie(0); cout.tie(0);cin >> n >> m;vector<int> a(n), s(n);for (int i = 0; i < n; ++i) {cin >> a[i] >> s[i];}auto check = [&](LL t) {std::vector<pair<LL, LL>> v;for (int i = 0; i < n; ++i) {if (t >= s[i]) v.push_back({a[i] - (t - s[i]), a[i] + (t - s[i])});}sort(v.begin(), v.end());if (sz(v) == 0 || v[0].first > 1) return false;LL r = v[0].second;for (int i = 1; i < sz(v); ++i) {if (v[i].first <= r + 1) r = max(r, v[i].second);else break;}return r >= m;};LL l = 1, r = 2e9;while (l < r) {LL mid = l + r >> 1;if (check(mid)) r = mid;else l = mid + 1;}cout << r << '\n';return 0;}
  • Java
import java.util.*;public class Main {    static int n, m;    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        n = sc.nextInt();        m = sc.nextInt();        int[] a = new int[n];        int[] s = new int[n];        for (int i = 0; i < n; ++i) {            a[i] = sc.nextInt();            s[i] = sc.nextInt();        }        long l = 1, r = 2_000_000_000;        while (l < r) {            long mid = l + r >>> 1;            if (check(mid, a, s)) r = mid;            else l = mid + 1;        }        System.out.println(r);    }    private static boolean check(long t, int[] a, int[] s) {        List<Pair<Long, Long>> v = new ArrayList<>();        for (int i = 0; i < n; ++i) {            if (t >= s[i]) {                v.add(new Pair<>(a[i] - (t - s[i]), a[i] + (t - s[i])));            }        }        v.sort(Comparator.comparingLong(Pair::getKey));        if (v.size() == 0 || v.get(0).getKey() > 1) return false;        long r = v.get(0).getValue();        for (int i = 1; i < v.size(); ++i) {            if (v.get(i).getKey() <= r + 1) r = Math.max(r, v.get(i).getValue());            else break;        }        return r >= m;    }    static class Pair<K, V> {        private final K key;        private final V value;        public Pair(K key, V value) {            this.key = key;            this.value = value;        }        public K getKey() {            return key;        }        public V getValue() {            return value;        }    }}
  • Python
n, m = map(int, input().split())a = []s = []for i in range(n):    a_i, s_i = map(int, input().split())    a.append(a_i)    s.append(s_i)def check(t):    v = []    for i in range(n):        if t >= s[i]:            v.append((a[i] - (t - s[i]), a[i] + (t - s[i])))    v.sort()    if len(v) == 0 or v[0][0] > 1:        return False    r = v[0][1]    for i in range(1, len(v)):        if v[i][0] <= r + 1:            r = max(r, v[i][1])        else:            break    return r >= ml = 1r = 2_000_000_000while l < r:    mid = (l + r) // 2    if check(mid):        r = mid    else:        l = mid + 1print(r)

来源地址:https://blog.csdn.net/m0_57487901/article/details/132741203

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

第十四届蓝桥杯省赛 Python B 组 D 题——管道(AC)

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

第十四届蓝桥杯大赛软件赛省赛(Java 大学B组)

目录 试题 A. 阶乘求和1.题目描述2.解题思路3.模板代码 试题 B.幸运数字1.题目描述2.解题思路3.模板代码 试题 C.数组分割1.题目描述2.解题思路3.模板代码 试题 D.矩形总面积1.问题描述2.解题思路
2023-08-16

第十三届蓝桥杯 Java C组省赛 C 题——纸张尺寸(AC)

1.纸张尺寸 1.题目描述 在 ISO 国际标准中定义了 A0 纸张的大小为 1189mm × 841mm, 将 A0 纸 沿长边对折后为 A1 纸, 大小为 841mm × 594mm, 在对折的过程中长度直接取 下整 (实际裁剪时可能有
2023-08-17

2023第十四届蓝桥杯Java B组个人题解

💎蓝桥杯系列文章 欢迎大家阅读蓝桥杯文章专栏🍄🍄 🔥2023第十四届蓝桥杯模拟赛第二期个人题解(Java实现) 🔥2023第十四届蓝桥杯模拟赛第三期个人题
2023-08-17

第十四届蓝桥杯模拟赛(第三期)Java组个人题解

第十四届蓝桥杯模拟赛(第三期)Java组个人题解 🌷 仰望天空,妳我亦是行人.✨ 🦄 个人主页——微风撞见云的博客🎐 🐳 《数据结构与算法》专栏的文章图文并茂ǹ
2023-08-17

第十四届蓝桥杯省赛JavaB组试题E【蜗牛】Dijkstra堆优化 or 线性DP?

                                                                                 🍏🍐🍊🍑&#x
2023-08-18

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录