1 条题解

  • 0
    @ 2026-5-17 10:57:38

    问题重述

    Bob 有 nn 件商品,每件商品有两个属性:

    • tit_i:收银员处理这件商品所需的时间(秒)
    • cic_i:这件商品的价格

    收银员一次只能处理一件商品,处理顺序由 Bob 决定。当收银员在处理某件商品时,Bob 可以偷走其他商品,偷一件恰好需要 11 秒。

    目标:最小化 Bob 实际支付的金额(即被收银员处理且未被偷走的商品的价格总和)。

    关键点

    • 如果某件商品的 ti=0t_i = 0,则当收银员处理它时,Bob 无法偷任何东西(因为处理时间为 00,没有时间偷)。
    • Bob 可以决定收银员处理商品的顺序。
    • 被偷的商品不需要支付。

    问题转化

    假设 Bob 决定让收银员处理 kk 件商品(其余 nkn - k 件被偷),设这些被处理商品的处理时间之和为 S=tiS = \sum t_i(只计算被处理的那 kk 件)。

    偷窃时间约束

    • 在处理一件商品的过程中,Bob 可以偷其他商品,每偷一件需要 11 秒。
    • 因此,总偷窃时间上限 = 总处理时间 SS(因为处理过程中 Bob 一直在偷)。
    • 需要偷的商品数量 = nkn - k

    可行性条件

    SnkS \ge n - k

    即:

    S+knS + k \ge n

    其中 kk 是被处理商品的数量,SS 是这些被处理商品的 tit_i 之和。


    更直观的理解

    我们换个角度:
    每件商品要么被支付(即被收银员处理),要么被偷

    • 如果一件商品被支付,它贡献 tit_i 秒的偷窃时间,并花费 cic_i 元。
    • 如果一件商品被偷,它需要消耗 11 秒偷窃时间,花费 00 元。

    TT = 所有被支付商品的 tit_i 之和,PP = 所有被支付商品的数量。

    约束:总偷窃时间 TT 必须 \ge 被偷商品数量 nPn - P,即:

    TnPT+PnT \ge n - P \quad \Rightarrow \quad T + P \ge n

    目标:最小化被支付商品的价格总和。


    动态规划解法

    这是一个 0/1 背包 变种。

    状态定义

    dp[j]dp[j] 表示:当被支付商品贡献的总时间 + 被支付商品的数量等于 jj 时,所需的最小支付金额。

    即:

    j=T+Pj = T + P

    其中 TT 是被支付商品的 tit_i 之和,PP 是被支付商品的数量。

    初始状态

    dp[0]=0dp[0] = 0,表示没有支付任何商品时,花费为 00
    其余 dp[j]=dp[j] = \infty

    状态转移

    对每件商品 (ti,ci)(t_i, c_i),我们考虑是否支付它:

    • 不支付(即偷走):不改变 TTPP,不影响 dpdp
    • 支付TT 增加 tit_iPP 增加 11,所以 jj 增加 ti+1t_i + 1,花费增加 cic_i

    因此转移方程为:

    $$dp[j + t_i + 1] = \min(dp[j + t_i + 1], dp[j] + c_i) $$

    为什么是 ti+1t_i + 1
    因为每支付一件商品,它既贡献 tit_i 秒偷窃时间,又自身作为被支付商品计入 PP,所以总“能力值” jj 增加了 ti+1t_i + 1

    答案

    我们需要 T+PnT + P \ge n,即 jnj \ge n
    因此答案为:

    ans=minj=nmax_sumdp[j]\text{ans} = \min_{j = n}^{\text{max\_sum}} dp[j]

    其中 max_sum\text{max\_sum}jj 可能的最大值。由于 ti2000t_i \le 2000n2000n \le 2000,最坏情况是支付所有商品:$j_{\max} = \sum t_i + n \le 2000 \times 2000 + 2000 = 4,002,000$,但实际我们只需取 n+max(ti)n + \max(t_i) 作为上界即可。


    算法步骤

    1. 读取 nn 和所有 (ti,ci)(t_i, c_i)
    2. 设定 M=n+2000M = n + 2000(足够大的上界)。
    3. 初始化 dpdp 数组,dp[0]=0dp[0] = 0,其余为 \infty
    4. 对每件商品,倒序遍历 jj(0/1 背包防止重复使用),执行转移:$$dp[j + t_i + 1] = \min(dp[j + t_i + 1], dp[j] + c_i) $$
    5. 最终答案为 minj=nMdp[j]\min_{j = n}^{M} dp[j]
    6. 输出答案。

    标程代码

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const ll INF = 1e18;
    
    int main() {
        int n;
        cin >> n;
        
        vector<int> t(n), c(n);
        int max_t = 0;
        for (int i = 0; i < n; i++) {
            cin >> t[i] >> c[i];
            max_t = max(max_t, t[i]);
        }
        
        // 最大可能的 j = n + max_t 足够(因为 T ≤ n * max_t 但我们只需考虑 j ≥ n)
        int max_sum = n + max_t;
        vector<ll> dp(max_sum + 1, INF);
        dp[0] = 0;
        
        for (int i = 0; i < n; i++) {
            // 倒序更新,确保每件商品只使用一次
            for (int j = max_sum; j >= 0; j--) {
                if (dp[j] != INF) {
                    int nj = min(max_sum, j + t[i] + 1);
                    dp[nj] = min(dp[nj], dp[j] + c[i]);
                }
            }
        }
        
        ll ans = INF;
        for (int j = n; j <= max_sum; j++) {
            ans = min(ans, dp[j]);
        }
        cout << ans << endl;
        
        return 0;
    }
    

    示例验证

    示例 1

    4
    2 10
    0 20
    1 5
    1 3
    

    商品列表:

    1. (t=2,c=10)(t=2, c=10)
    2. (t=0,c=20)(t=0, c=20)
    3. (t=1,c=5)(t=1, c=5)
    4. (t=1,c=3)(t=1, c=3)

    最优方案:支付商品 1、3、4,总时间 T=2+1+1=4T = 2 + 1 + 1 = 4,支付数量 P=3P = 3T+P=74T + P = 7 \ge 4,总花费 10+5+3=810 + 5 + 3 = 8

    示例 2

    3
    0 1
    0 10
    0 100
    

    所有 ti=0t_i = 0,支付任何商品都不产生偷窃时间。
    要满足 T+PnT + P \ge n,即 0+P30 + P \ge 3,必须支付所有 33 件,花费 1+10+100=1111 + 10 + 100 = 111


    复杂度分析

    • 时间复杂度:$O(n \cdot (n + \max t_i)) \approx 2000 \times 4000 = 8 \times 10^6$,完全可以接受。
    • 空间复杂度:O(n+maxti)4000O(n + \max t_i) \approx 4000,很小。

    总结

    本题的关键在于将问题转化为 0/1 背包,并定义状态 j=T+Pj = T + P(总处理时间 + 支付商品数量)。
    这样,可行性条件 T+PnT + P \ge n 就变成了 jnj \ge n,非常简洁。
    转移时每件商品贡献 ti+1t_i + 1jj,花费 cic_i,最后取 minjndp[j]\min_{j \ge n} dp[j] 即为答案。

    • 1

    信息

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