博弈论 / 贪心 / 后缀和优化
关键点: Bessie 想让 Elsie 输,所以 Bessie 会采取最优策略(对 Elsie 最不利)。
我们需要在最坏情况下存活!
对于第 $i$ 回合,给定 $K$ 个数字,我们需要算出 Elsie 选 Even 或 Odd 的最坏结果 (Delta)。
我们计算两个数组:
单纯的贪心(只看当前能不能活)是不够的。
我们需要回答:"如果我这一步走了,剩下的血量够不够扛过未来所有回合的最优解中可能出现的最坏低谷?"
定义 $min\_psum[i]$:从第 $i$ 回合开始到结束,假设我们每一步都选最优策略 ($u[k]$),过程中累计和的最低点是多少?
假设 u 数组 (每回合最佳变化) 为: $[-3, +5, -4, +2]$
User Code Logic: $min\_psum[i] = \min(0LL, min\_psum[i+1] + u[i])$
从 $i = 0$ 到 $M-1$ 遍历:
Step 1: 尝试选 Even (优先)
如果都满足 $\rightarrow$ 选 Even,更新 Current。
Step 2: 否则尝试选 Odd
Step 3: 都不行? $\rightarrow$ 输出 -1。
使用 C++ 实现上述逻辑。
// 计算每一轮选Odd或Even的最坏结果
for (int i = 0; i < m; i++) {
bool odd = false, even = false;
int min_odd = 1e9, min_even = 1e9;
int max_odd = -1e9, max_even = -1e9;
// ... 读取K个数,更新min/max ...
// v[i][0]: 选Even的变化量
// 如果有奇数,Bessie会选最大的奇数让你减分 (-max_odd)
// 如果只有偶数,Bessie只能选最小的偶数让你加分 (+min_even)
v[i][0] = odd ? -max_odd : min_even;
// v[i][1]: 选Odd的变化量
v[i][1] = even ? -max_even : min_odd;
// u[i]: 这一轮如果我选得好,最坏情况下的最好结果
u[i] = max(v[i][0], v[i][1]);
}
// min_psum[i] 表示从i到m,累积和相对于i时刻的最小下降值
min_psum[m] = 0;
for (int i = m-1; i >= 0; i--)
min_psum[i] = min(0LL, min_psum[i+1] + u[i]);
bool ok = true;
for (int i = 0; i < m; i++) {
// 尝试 Even (字典序小,优先)
// 1. 当前不死: n + v[i][0] > 0
// 2. 未来不死: n + v[i][0] + min_psum[i+1] > 0
if (n + v[i][0] > 0 && n + v[i][0] + min_psum[i+1] > 0) {
ans[i] = 0; // Record Even
n += v[i][0];
}
// 尝试 Odd
else if (n + v[i][1] > 0 && n + v[i][1] + min_psum[i+1] > 0) {
ans[i] = 1; // Record Odd
n += v[i][1];
} else {
ok = false; break;
}
}