1 条题解

  • 0
    @ 2026-4-15 18:18:06

    D. 猫头鹰塞拉芬 详细题解

    题目核心理解

    一开始有 nn 个人排队,Kirill 站在第 n+1n+1 位(队尾)。 他可以多次向前插队,规则如下:

    • 若当前在位置 ii,可以跳到任意前面位置 j(j<i)j(j<i)
    • 要给 jj 位置的人支付 aja_j
    • 对中间每一个人 k(j<k<i)k(j<k<i),支付 bkb_k
    • 要求最终停在前 mm 个位置(1fm1\le f\le m); 求最少花费金币数

    核心思路

    1. 关键贪心观察

    对于任意一个人 kk

    • 如果 bk>akb_k > a_k:只给他付 bkb_k 是不划算的,应该尽量直接交换到这里,只付 aka_k
    • 如果 bk<akb_k < a_k:经过他时付 bkb_k 更便宜,没必要专门交换。

    所以最优策略是:

    • 只在满足 aj<bja_j < b_jj>mj>m 的位置交换;
    • 这些位置能跳就跳,能最大程度省钱;
    • 跳到不能再跳时,直接枚举前 mm 个位置取最小花费。

    2. 花费计算

    ii 跳到 jj 的花费为:

    cost=aj+k=j+1i1bkcost = a_j + \sum_{k=j+1}^{i-1}b_k

    前缀和可以 O(1)O(1) 求出区间 bb 的和。

    3. 最终收尾

    当前方没有满足 aj<bja_j < b_jj>mj>m 的位置时:

    • 直接枚举 1m1\sim m 所有位置;
    • 计算停在每个位置的总花费;
    • 取最小值即为答案。

    算法流程

    1. 预处理 bb 数组的前缀和 sumbsum_b
    2. 从队尾 now=n+1now = n+1 开始向前贪心跳跃;
    3. 每次寻找第一个 j<nowj<now,满足 aj<bja_j < b_jj>mj>m
    4. 若找到,计算跳跃花费并更新最小值,将 nownow 设为 jj
    5. 若找不到,退出贪心阶段;
    6. 从当前位置向前遍历到 11,累加 bkb_k,并对所有 fmf\le m 更新最小花费;
    7. 输出最小花费。

    公式与复杂度分析

    单次跳跃花费:

    cost=aj+(sumb[i1]sumb[j])cost = a_j + (sum_b[i-1] - sum_b[j])

    遍历过程总花费递推:

    total=total+bktotal = total + b_k

    fmf\le mtotal+aftotal+a_f 更新答案。

    复杂度

    • 前缀和预处理:O(n)O(n)
    • 贪心跳跃:每个位置至多访问一次 O(n)O(n)
    • 最后遍历:O(n)O(n)

    总时间复杂度:O(n)O(n)。 可轻松处理 n2×105n\le 2\times 10^5、多组数据总长度不超过 2×1052\times 10^5 的范围。

    • 1

    信息

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