1 条题解

  • 0
    @ 2026-4-13 10:40:25

    题目详细题解

    问题重述

    给定一个长度为 nn 的数组 aa,表示每条跑道的路段数。
    对于每个查询 (l,u)(l, u),需要选择一个 rlr \ge l,使得完成第 llrr 条跑道总共 k=i=lraik = \sum_{i=l}^r a_i 个路段后,能力的总增加量最大。

    能力增加规则:
    完成第 11 段增加 uu,第 22 段增加 u1u-1,……,第 kk 段增加 u+1ku+1-k

    因此总增加量为:

    $$f(k) = \sum_{j=1}^{k} (u+1-j) = k \cdot u - \frac{k(k-1)}{2} $$

    其中 k=i=lraik = \sum_{i=l}^r a_i


    核心观察

    1. f(k)f(k) 的性质
      f(k)f(k) 是一个关于 kk 的二次函数:

      $$f(k) = -\frac{1}{2}k^2 + \left(u + \frac{1}{2}\right)k $$

      它是开口向下的抛物线,对称轴在 k=u+0.5k = u + 0.5 附近。
      即:当 kuk \le u 时,f(k)f(k)kk 增加而增加;
      kk 超过 uu 很多时,f(k)f(k) 会下降。

    2. 最优 kk 的位置
      由于 f(k)f(k) 先增后减,最优的 kk 应该在 uu 附近。
      具体来说:

      • 如果总路段数 kuk \le u,那么每一段的增加量都是非负的,继续增加路段一定更好。
      • k>uk > u 时,后面会出现负增益,但总增加量可能仍然比 kuk \le u 时大(例如 u=5u=5k=6k=6 时最后一段 +0+0,总和不减;k=7k=7 时最后一段 1-1,但前面仍然有 66 段正增益)。
    3. 关键结论(来自标程思路)
      对于固定的 lluu

      • 找到最大的 rr,使得总路段数 kuk \le u,记这个 rrr0r_0
      • 最优的 rr 只可能在 r0r_0r0+1r_0+1(甚至附近小范围)中产生。
      • 更远的 rr 由于 kk 远大于 uu,负增益太多,不可能更优。

      为什么?因为 f(k)f(k)ku+1k \ge u+1 时开始递减,且递减速度加快。
      所以只需要检查 r0r_0r0+1r_0+1 两个候选即可。

      但为了安全(防止边界情况),标程检查了 r0r_0 附近 ±2\pm 2 的范围。


    算法步骤

    1. 预处理前缀和

    ps[i]=j=1iajps[i] = \sum_{j=1}^i a_j,则从 llrr 的总路段数为:

    k=ps[r]ps[l1]k = ps[r] - ps[l-1]

    2. 对于每个查询 (l,u)(l, u)

    第一步:二分查找最大的 rr 使得 kuk \le u

    lb = l, rb = n;
    while(lb < rb) {
        int mid = (lb + rb + 1) >> 1;
        if(ps[mid] - ps[l-1] <= u) 
            lb = mid;
        else 
            rb = mid - 1;
    }
    

    这里 lblb 就是我们要的 r0r_0

    第二步:在 r0r_0 附近小范围枚举最优解

    检查 i[max(l,r02),min(n,r0+2)]i \in [\max(l, r_0-2), \min(n, r_0+2)]

    int t = ps[i] - ps[l-1];
    int ut = (u + (u - t + 1)) * t / 2;
    

    这里的 ut 计算了 f(k)f(k)

    $$f(t) = u + (u-1) + \dots + (u-t+1) = \frac{(u + (u-t+1)) \cdot t}{2} $$

    这是等差数列求和公式。

    第三步:选择 f(k)f(k) 最大的 rr,若相等选最小的 rr

    由于我们按 ii 从小到大枚举,当 ut > maxu 时才更新,自然保证了相等时取较小下标。


    为什么只检查附近几个点?

    因为 f(k)f(k) 是单峰函数(先增后减),峰值在 k=uk = uu+1u+1 附近。
    kk 只能取前缀和的值,这些值不是连续的,但 r0r_0 对应最大的 kuk \le ur0+1r_0+1 对应最小的 k>uk > u
    最优解一定在这两个 kk 对应的 rr 中。
    再往外,f(k)f(k) 只会更小。

    检查 ±2\pm 2 是为了处理边界情况(例如 ar0+1a_{r_0+1} 很大导致 kk 跳过 uu 较远)。


    复杂度分析

    • 前缀和:O(n)O(n)
    • 每个查询:二分 O(logn)O(\log n) + 常数次检查
    • 总复杂度:O((n+q)logn)O((n+q)\log n),满足题目要求。

    示例验证(第一个查询)

    a=[3,1,4,1,5,9],l=1,u=8a = [3,1,4,1,5,9], l=1, u=8

    • ps=[0,3,4,8,9,14,23]ps = [0,3,4,8,9,14,23]
    • 二分找到最大的 rr 使 ps[r]ps[0]8ps[r]-ps[0] \le 8r=3r=3k=8k=8
    • 检查 r=2,3,4r=2,3,4
      • r=2,k=4r=2, k=4f=(8+5)4/2=26f = (8+5)\cdot4/2 = 26
      • r=3,k=8r=3, k=8f=(8+1)8/2=36f = (8+1)\cdot8/2 = 36
      • r=4,k=9r=4, k=9f=(8+0)9/2=36f = (8+0)\cdot9/2 = 36
    • 最大值为 3636,取最小 rr33

    输出 33,与题意一致。


    总结

    这道题的核心是:

    1. 将问题转化为二次函数求最值。
    2. 利用前缀和快速得到总路段数。
    3. 二分找到 kuk \le u 的最大 rr
    4. 只在 rr 附近检查几个候选点,因为单峰函数的最值就在峰顶附近。

    标程的实现非常简洁高效,是典型的 二分 + 数学 题目。

    • 1

    信息

    ID
    6506
    时间
    1000ms
    内存
    256MiB
    难度
    8
    标签
    递交数
    0
    已通过
    0
    上传者