📚 算法笔记:B-小紫的劣势博弈 (牛客周赛 Round 85)
1. 题目简述
- 初始状态 : x = 0 x = 0 x=0,给定一个长度为 n n n 的正整数数组。
- 操作规则 :小红(先手)和小紫轮流取走一个数。小红取走 a i a_i ai 则 x + a i x + a_i x+ai,小紫取走 a i a_i ai 则 x − a i x - a_i x−ai。
- 目标函数 :小红希望最终 x x x 最小 ,小紫希望最终 x x x 最大。
- 求解 :双方均采取最优策略时,最终 x x x 的值。
2. 核心代码 (C++ 实现)
c++
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// 建议将 sum 放在 solve 内部或每次手动清零,以应对多组数据
ll sum = 0;
void solve()
{
ll cnt;
if (!(cin >> cnt)) return;
// 关键:在读入 cnt 之后再定义 vector 的大小
vector<ll> a(cnt);
for (int i = 0; i < cnt; i++)
{
cin >> a[i];
}
// 1. 核心策略:排序。因为双方都想保护大数不被对方操作,所以都会抢夺当前最小的数
sort(a.begin(), a.end());
sum = 0; // 初始化累加器
for(int i = 0; i < cnt; i++)
{
// 2. 模拟博弈过程
if(i % 2 == 0)
{
sum += a[i]; // 第 1, 3, 5... 次操作由先手小红执行
}
else
{
sum -= a[i]; // 第 2, 4, 6... 次操作由后手小紫执行
}
}
cout << sum << endl;
}
int main()
{
// 提高 IO 效率
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int _ = 1;
// cin >> _; // 若题目存在多组数据测试,取消此行注释
while(_--)
{
solve();
}
return 0;
}
3. 核心考点与注意事项
- 贪心博弈转化 :
- 小红要加数,但希望结果小 → \rightarrow → 她会优先消耗数组中最小的数。
- 小紫要减数,但希望结果大 → \rightarrow → 为了减得少,她也会优先消耗数组中最小的数。
- 结论 :双方的目标虽然相反,但行为达成了一致------按升序依次取数。
- 数值范围 : n = 10 5 n=10^5 n=105 且 a i = 10 9 a_i=10^9 ai=109,累加和
sum必须使用long long。 - 排序效率 :使用
std::sort,时间复杂度为 O ( n log n ) O(n \log n) O(nlogn),足以通过 10 5 10^5 105 级别的数据。
4. 易错点回顾 (My Mistakes)
1. 全局 Vector 的初始化陷阱
- 错误经历 :曾尝试在全局定义
vector<ll> a(cnt)。- 后果 :由于程序启动时全局变量
cnt默认为 0,会导致vector初始化大小为 0。即使后续在solve函数中给cnt赋值,vector也不会自动扩容,导致访问越界。- 修正 :必须在读入
cnt之后,使用vector<ll> a(cnt)局部定义或a.resize(cnt)。2. 全局变量的残留问题
- 错误经历 :将
sum定义为全局变量且未在solve开始时清零。- 后果 :如果题目给出的测试数据组数
_ > 1,第二次计算的结果会叠加上一次的残余值。- 修正 :局部变量优先原则 。能写在
solve里的变量尽量不要写在外面。