1 条题解
-
0
问题重述
Bob 有 件商品,每件商品有两个属性:
- :收银员处理这件商品所需的时间(秒)
- :这件商品的价格
收银员一次只能处理一件商品,处理顺序由 Bob 决定。当收银员在处理某件商品时,Bob 可以偷走其他商品,偷一件恰好需要 秒。
目标:最小化 Bob 实际支付的金额(即被收银员处理且未被偷走的商品的价格总和)。
关键点:
- 如果某件商品的 ,则当收银员处理它时,Bob 无法偷任何东西(因为处理时间为 ,没有时间偷)。
- Bob 可以决定收银员处理商品的顺序。
- 被偷的商品不需要支付。
问题转化
假设 Bob 决定让收银员处理 件商品(其余 件被偷),设这些被处理商品的处理时间之和为 (只计算被处理的那 件)。
偷窃时间约束:
- 在处理一件商品的过程中,Bob 可以偷其他商品,每偷一件需要 秒。
- 因此,总偷窃时间上限 = 总处理时间 (因为处理过程中 Bob 一直在偷)。
- 需要偷的商品数量 = 。
可行性条件:
即:
其中 是被处理商品的数量, 是这些被处理商品的 之和。
更直观的理解
我们换个角度:
每件商品要么被支付(即被收银员处理),要么被偷。- 如果一件商品被支付,它贡献 秒的偷窃时间,并花费 元。
- 如果一件商品被偷,它需要消耗 秒偷窃时间,花费 元。
设 = 所有被支付商品的 之和, = 所有被支付商品的数量。
约束:总偷窃时间 必须 被偷商品数量 ,即:
目标:最小化被支付商品的价格总和。
动态规划解法
这是一个 0/1 背包 变种。
状态定义
设 表示:当被支付商品贡献的总时间 + 被支付商品的数量等于 时,所需的最小支付金额。
即:
其中 是被支付商品的 之和, 是被支付商品的数量。
初始状态
,表示没有支付任何商品时,花费为 。
其余 。状态转移
对每件商品 ,我们考虑是否支付它:
- 不支付(即偷走):不改变 和 ,不影响 。
- 支付: 增加 , 增加 ,所以 增加 ,花费增加 。
因此转移方程为:
$$dp[j + t_i + 1] = \min(dp[j + t_i + 1], dp[j] + c_i) $$为什么是 ?
因为每支付一件商品,它既贡献 秒偷窃时间,又自身作为被支付商品计入 ,所以总“能力值” 增加了 。答案
我们需要 ,即 。
因此答案为:其中 是 可能的最大值。由于 ,,最坏情况是支付所有商品:$j_{\max} = \sum t_i + n \le 2000 \times 2000 + 2000 = 4,002,000$,但实际我们只需取 作为上界即可。
算法步骤
- 读取 和所有 。
- 设定 (足够大的上界)。
- 初始化 数组,,其余为 。
- 对每件商品,倒序遍历 (0/1 背包防止重复使用),执行转移:$$dp[j + t_i + 1] = \min(dp[j + t_i + 1], dp[j] + c_i) $$
- 最终答案为 。
- 输出答案。
标程代码
#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、3、4,总时间 ,支付数量 ,,总花费 。
示例 2
3 0 1 0 10 0 100所有 ,支付任何商品都不产生偷窃时间。
要满足 ,即 ,必须支付所有 件,花费 。
复杂度分析
- 时间复杂度:$O(n \cdot (n + \max t_i)) \approx 2000 \times 4000 = 8 \times 10^6$,完全可以接受。
- 空间复杂度:,很小。
总结
本题的关键在于将问题转化为 0/1 背包,并定义状态 (总处理时间 + 支付商品数量)。
这样,可行性条件 就变成了 ,非常简洁。
转移时每件商品贡献 到 ,花费 ,最后取 即为答案。
- 1
信息
- ID
- 7147
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者