acwing:寒假每日一题(1)

本文介绍了如何解决蓝桥杯省赛中关于水管填充的最短时间问题,利用二分查找确定每个时刻水阀能检测的范围,并通过区间合并检查是否覆盖整个管道。关键代码展示了如何处理区间合并和数据范围问题。
摘要由CSDN通过智能技术生成

来源:第十四届蓝桥杯省赛PythonB组\5407. 管道

2024寒假每日一题全部题解传送门>>

题目描述:

题意理解:

每一段都有可开关的水阀和检测水流的传感器,但并不是每个水阀都会打开,只有输入的L(i)会在S(i)时刻打开,我们要求的就是水流满整个管道的最短时间。

 思路:

假如在t时刻满足题目要求, 那么比t大的时刻也一定满足要求,具有单调性。我们就可以想到用二分来查找每个时刻,并将每个时刻每个水阀能检测的范围算出来。此时问题就变成了对于这些所检测出来的范围是否能覆盖整个管道,所以我们又想到将这些区间合并,看看该区间能否覆盖所有位置。

 注意细节:

  1. 二分的数据范围:根据题目S(i) 所给的数据范围,左端点是1,右端点为2e9
  2. 此题的区间合并并不是两个区间有交集才能合并,例如[1, 2]和[3, 4]也可以进行合并成[1, 4]
  3. 注意数据范围,需要用long long
#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
vector<vector<int>> w;  //存Li水阀能在Si时刻打开

int n, m;

bool check(LL mid) {
    vector<vector<int>> segs;
    
    for (int i = 0; i < n ; i ++ ) {
        int L = w[i][0], S = w[i][1];
        if (S <= mid) {     // 当前的时刻大于水闸打开的时刻,此时改水闸已经打开
        
            // 当前水闸可以检测到的范围
            int t = mid - S;
            int l = max(1, L - t), r = min((LL)L + t, (LL)m);   //这里也注意long long, int可能爆
            
            segs.push_back({l, r});
        }
    }
    
    sort(segs.begin(), segs.end()); //默认按左端点排序
    
    int ed = -1, st = -1;
    for(int i = 0; i < segs.size(); i ++) // 将所有水闸可以检测到的范围进行区间合并
    {
        if (segs[i][0] <= ed + 1) ed = max(ed, segs[i][1]);
        else st = segs[i][0], ed = segs[i][1];
    }

    return ed == m && st == 1;
}

int main() {
    cin >> n >> m;  // 砸门数和管道数
    
    for (int i = 0; i < n; i ++ ) {
        int l, s;
        cin >> l >> s;
        w.push_back({l, s});
    }
    
    LL l = 0, r = 2e9;
    
    while (l < r) { //二分查找最短时间
        int mid = (LL) l + r >> 1;  //用int可能会爆,记得使用long long
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    cout << r ;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值