1 条题解
-
0
题目解析
问题重述
有 个宝箱,第 个宝箱初始有 枚硬币。你可以向任意宝箱添加非负整数数量的硬币,但添加后所有宝箱的硬币总数必须至少为 。
然后 Monocarp 会贪婪地取宝箱:每次选择当前硬币数最多的宝箱,直到取到的硬币总数 为止。
你需要通过添加硬币,使得 Monocarp 停止时取到的硬币数恰好等于 。求最少需要添加多少硬币。
关键思路
核心观察: 假设我们不添加任何硬币,Monocarp 会按照初始硬币数从大到小依次取宝箱。设他取完若干个最大宝箱后,总数为 ,且 ,但再取下一个宝箱就会超过 。此时,如果我们将目前取到的宝箱中最大的那个增加 枚硬币,那么:
- 这组宝箱的总数变为
- 由于最大宝箱变大了,它仍会被先取到,且取完这组宝箱后总数刚好 ,Monocarp 就会停止
- 添加的硬币数就是
为什么只考虑增大当前已取宝箱中的最大值?
假设我们试图增大某个不在当前集合中的宝箱 (初始值为 ),使得它代替集合中的某个宝箱 ()被取到。为了让宝箱 在 之前被取,必须满足 ,需要添加 。而如果我们直接增大宝箱 ,添加更少的硬币()就能达到目的。因此,改变取宝箱的顺序不是最优的。
结论: 最优策略是:
- 将 从大到小排序
- 从大到小累加,找到最大的 ,即取前若干个最大宝箱,使得总和不超过 但再加下一个就会超过
- 答案就是
算法步骤
- 读入 个测试用例
- 对每个测试用例:
- 读入 和
- 读入数组 ,长度为
- 将 按从大到小排序
- 初始化
- 遍历排序后的数组:
- 如果 ,则
- 否则跳出循环
- 输出
时间复杂度
排序:,,非常快。 总复杂度:
示例验证
例1:
- 排序降序:
- 取 ,,下一个 会使 ,停止
例2:
- 排序降序:
- 取 ,;取 ,;取 ,;下一个 会使 ,停止
例3:
- 排序降序:
- 取 ,;取 ,;结束(没有更多宝箱)
例4:
- 排序降序:
- 取 ,;取 ,;下一个 会使 ,停止
C++ 代码
#include <bits/stdc++.h> using namespace std; int main() { int t; cin >> t; while (t--) { int n, k; cin >> n >> k; vector<int> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } // 按从大到小排序 sort(a.begin(), a.end(), greater<int>()); int sum = 0; for (int i = 0; i < n; i++) { if (sum + a[i] <= k) { sum += a[i]; } else { break; } } cout << k - sum << '\n'; } return 0; }
- 1
信息
- ID
- 7055
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 3
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者