原题链接:蓝桥杯2023年第十四届省赛真题-管道
首先根据题意,假如说在t时刻满足题目要求,那么比t大的时刻也一定满足要求,故具有单调性,此时可以想到用二分来做。
对于每个二分出来的时刻,可以将每一个水阀所能检测的范围算出来(若该时刻小于水阀打开的时刻,则该水阀跳过)。此时问题就变成了对于这些所检测出来的范围是否能覆盖整个管道,显然是一个区间合并知识点。将所有区间合并之后,再看看该区间是否能覆盖11~len的位置即可。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <vector> #include <queue> #define x first #define y second using namespace std; using ll = long long; typedef pair<int, int> PII; const int N = 1e5 + 3; int n, m; // n表示水阀数量,m表示管道长度 PII w[N], q[N]; // 定义长度为N的水阀数组w,和临时数组q bool check(int mid) { int cnt = 0; // 初始化计数器为0,用于统计每个水阀的有效区间 for (int i = 1; i <= n; i++) { int L = w[i].x, S = w[i].y; // 获取当前水阀的位置L和打开时间S if (mid >= S) // 如果mid大于等于水阀打开时间S { int t = mid - S; // 计算时间差 int l = max(1, L - t), r = min((ll)m, (ll)L + t); // 计算有效区间的左右边界 q[cnt++] = {l, r}; // 将有效区间更新到临时数组q中 } } sort(q, q + cnt); // 对有效区间进行排序 int st = -1, ed = -1; // 初始化起点和终点 for (int i = 0; i < cnt; i++) // 遍历有效的区间 { if (q[i].x <= ed + 1) // 如果当前区间的左边界小于等于前一个区间的右边界+1 ed = max(ed, q[i].y); // 更新终点 else st = q[i].x, ed = q[i].y; // 否则更新起点和终点 } return st == 1 && ed == m; // 返回有效区间是否覆盖了整个管道 } int main() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); // 加速输入输出 cin >> n >> m; // 读取水阀数量和管道长度 for (int i = 1; i <= n; i++) // 遍历水阀 cin >> w[i].x >> w[i].y; // 读取每个水阀的位置和打开时间 ll l = 0, r = 2e9; // 初始化左边界l为0,右边界r为2e9 while (l < r) // 二分查找 { ll mid = l + r >> 1; // 计算中点 if (check(mid)) // 调用函数检查中点是否符合要求 r = mid; // 更新右边界 else l = mid + 1; // 更新左边界 } cout << r; // 输出结果 return 0; // 返回0,表示程序执行成功 }
0.0分
1 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复