1 条题解
-
0
题目重述
有 个物品,第 个物品的价格为 。Alice 和 Bob 轮流拿物品,Alice 先手,每人每次拿一个,直到拿完。
设 为 Alice 拿的物品总价, 为 Bob 拿的物品总价,得分为 。Alice 想最大化得分,Bob 想最小化得分,两人都采取最优策略。在游戏开始前,Bob 可以增加若干物品的价格(只能增加,不能减少),总增加量不超过 。
问:Bob 通过最优的修改和最优的游戏策略,能实现的最小可能得分是多少?
第一步:确定不修改时的最优策略
这是一个经典的轮流取物博弈。
因为 Alice 想最大化 ,Bob 想最小化 ,且两人都能看到所有物品的价格,最优策略是每次取当前最大的物品。证明思路:
- 考虑任意一步,轮到某玩家时,如果他拿的不是最大的,对方下一步可以拿走最大的,这对当前玩家不利。
- 因此,双方都会贪心地拿当前最大值。
所以,将价格按降序排序后,物品顺序为:
那么:
- Alice 拿 (下标为偶数的物品)
- Bob 拿 (下标为奇数的物品)
初始得分(不修改时)为:
$$S_0 = \sum_{i=0}^{\lfloor (n-1)/2 \rfloor} b_{2i} \;-\; \sum_{i=0}^{\lfloor (n-2)/2 \rfloor} b_{2i+1} $$
第二步:Bob 修改的影响
Bob 只能增加物品的价格。
如果他增加的是 Alice 会拿的物品,那么 增加,得分 增加,对他不利。
所以 Bob 只会增加自己会拿的物品(即奇数下标 )。设 Bob 将某个自己拿的物品 增加 (),则 增加 ,得分 减少 。
因此,Bob 每增加 单位价格到自己的物品上,得分就减少 。
他的目标是在总增加量 的前提下,尽可能多地减少得分。
第三步:Bob 能增加的极限
Bob 不能无限制地增加自己的物品,因为增加太多可能超过前一个 Alice 拿的物品,这不会带来额外的好处吗?
注意:如果 增加到超过 ,那么排序顺序会改变,后续的分配也会改变。但游戏是在修改后的价格上进行的,双方仍会按降序贪心取。关键结论:Bob 增加自己的物品,最多只能增加到等于前一个 Alice 物品的价格(即 ),因为:
- 如果 ,增加它直到 是有效的,每增加 减少得分 。
- 如果 ,再增加只会让自己物品超过前面的,但排序后它可能会跑到前面去,成为 Alice 拿的?这需要分析。
实际上,更严谨的推导(官方题解)表明:
Bob 最多能让每个自己的物品 增加到 ,但超过 没有意义,因为如果 ,那么排序后 会跑到 前面,导致 Alice 拿这个更大的,反而更糟。
所以 Bob 只会增加自己物品到不超过前一个 Alice 物品的价格。因此,对于每个 (),Bob 能从这个物品上获得的最大减少量为:
第四步:分配
Bob 的总减少量不能超过 ,也不能超过 。
因为每增加 单位到任意自己物品上,得分就减少 ,且收益相同,所以 Bob 可以任意分配 到这些 上,只要不超过各自的 。因此,Bob 能实现的最大减少量为:
$$R = \min\left(k,\; \sum_{i=0}^{\lfloor (n-2)/2 \rfloor} \max(0,\; b_{2i} - b_{2i+1})\right) $$
第五步:最终答案
初始得分为 ,Bob 能减少 ,因此最终得分为:
第六步:算法步骤
- 将数组 按降序排序,得到 。
- 计算初始得分:$$S_0 = \sum_{i=0}^{\lfloor (n-1)/2 \rfloor} b_{2i} - \sum_{i=0}^{\lfloor (n-2)/2 \rfloor} b_{2i+1} $$
- 计算可减少总量:$$\text{can\_reduce} = \sum_{i=0}^{\lfloor (n-2)/2 \rfloor} \max(0,\; b_{2i} - b_{2i+1}) $$
- 实际减少量:
- 输出:
第七步:验证样例
样例1
排序:
✅样例2
排序:
(只有 ,因为 )
✅样例3
排序:
✅样例4
排序:
✅
第八步:最终代码(标程)
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { int n; long long k; cin >> n >> k; vector<long long> a(n); for (int i = 0; i < n; ++i) { cin >> a[i]; } // 降序排序 sort(a.rbegin(), a.rend()); // 计算初始得分 long long score = 0; for (int i = 0; i < n; ++i) { if (i % 2 == 0) { score += a[i]; } else { score -= a[i]; } } // 计算 Bob 能获得的最大减少量 long long can_reduce = 0; for (int i = 1; i < n; i += 2) { can_reduce += max(0LL, a[i-1] - a[i]); } long long reduce = min(k, can_reduce); score -= reduce; cout << score << "\n"; } return 0; }
复杂度分析
- 排序 ,所有测试用例总和 $O(\sum n \log n) \le O(2\times10^5 \log 2\times10^5)$。
- 空间复杂度 。
- 1
信息
- ID
- 7224
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者