1 条题解

  • 0
    @ 2026-6-19 10:31:09

    📝 题目大意

    有一座长度为 LL 的桥,每块防护布长度为 WW。已有 NN 块防护布铺设在桥上的某些位置(位置严格递增),每块布覆盖区间 [ai,ai+W][a_i, a_i+W]。求最少还需要多少块防护布,才能使得桥的每一段 [0,L][0, L] 都被覆盖。

    💡 解题思路

    1. 题目分析N105N \le 10^5L,W1018L, W \le 10^{18},需要 O(N)O(N)O(NlogN)O(N \log N) 的解法。已有的 NN 块布的位置 aia_i 是严格递增的,且 0aiLW0 \le a_i \le L-W。问题本质是扫描已覆盖的区间,找出所有未被覆盖的"空隙"。

    2. 算法推导

      • 将桥的右端点 LL 视作一个虚拟的"已铺布位置"(a.push_back(L)),这样可以将"最后一个空隙"(即最后一块布到桥尾之间的部分)统一处理。
      • 从左到右扫描,依次检查相邻两块布之间的空隙:
        • i1i-1 块布覆盖 [ai1,ai1+W][a_{i-1}, a_{i-1}+W],第 ii 块布覆盖 [ai,ai+W][a_i, a_i+W]
        • ai1+Waia_{i-1}+W \ge a_i,说明两块布覆盖范围有重叠或恰好相接,中间没有空隙。
        • ai1+W<aia_{i-1}+W < a_i,说明存在空隙 [ai1+W,ai)[a_{i-1}+W, a_i),空隙长度为 aiai1Wa_i - a_{i-1} - W
        • 填补该空隙需要的最少布数为 aiai1WW\lceil \frac{a_i - a_{i-1} - W}{W} \rceil,等价于整数除法 aiai11W\frac{a_i - a_{i-1} - 1}{W}(推导:XW=X+W1W\lceil \frac{X}{W} \rceil = \frac{X+W-1}{W},代入 X=aiai1WX = a_i - a_{i-1} - W 即得)。
      • 起点到第一块布之间的空隙单独处理:需要 $\lceil \frac{a_0}{W} \rceil = \frac{a_0 + W - 1}{W}$ 块布来覆盖 [0,a0)[0, a_0)
      • 累加所有空隙所需的布数即为答案。
    3. 边界与细节

      • a0=0a_0 = 0:第一块布从桥头开始,公式 a0+W1W\frac{a_0+W-1}{W} 结果为 00,无需额外布。
      • 最后一块布已覆盖桥尾:当 aN1+WLa_{N-1}+W \ge L 时,a.push_back(L) 后条件 a[N-1]+W < a[N] 不成立,不会额外计数。
      • 数据范围L,W1018L, W \le 10^{18},必须使用 long long(C++ 中 int64_t)。标准代码中通过 #define int long long 统一处理。
      • 整数除法:C++ 中正整数除法自动向下取整,公式 aiai11W\frac{a_i - a_{i-1} - 1}{W} 恰好等价于所需的上取整结果。

    ⏱️ 复杂度分析

    • 时间复杂度O(N)O(N),仅需一次线性扫描。
    • 空间复杂度O(N)O(N),存储 NN 个位置(使用 vector)。

    💻 标准代码 (C++)

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long  // 数据范围可达 1e18,统一使用 64 位整数
    void solve(){
        int n, l, w;
        cin >> n >> l >> w;
        vector<int> a(n);
        for(int& i : a) cin >> i;
        a.push_back(l);  // 将桥尾 L 作为虚拟位置,统一处理最后一个空隙
    
        // 计算从起点 0 到第一块布之前所需的布数:ceil(a[0] / w)
        int ans = (a[0] + w - 1) / w;
    
        // 扫描相邻两块布,累加空隙所需的布数
        for(int i = 1; i <= n; i++){
            if(a[i-1] + w < a[i])  // 存在空隙
                ans += (a[i] - a[i-1] - 1) / w;  // ceil((a[i] - a[i-1] - w) / w)
        }
        cout << ans << '\n';
    }
    int32_t main(){
        int t = 1;
        while(t--) solve();
        return 0;
    }
    

    信息

    ID
    871
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    (无)
    递交数
    1
    已通过
    1
    上传者