题目
小 L 和小 Q 在玩一个策略游戏。具体规则这里就不复述了,大家可以翻阅原题。
思路分析
考场上见到这种题,第一反应往往是'这得写个博弈搜索吧'。但其实冷静下来推一推,大部分策略游戏都落在几个经典模型里——Nim、SG 函数,或者直接区间 DP。
以这道题来说,关键是想清楚每一步状态如何转移。如果给的是一个数组,每人每次可以取走一个数,最终得分总和最大的人胜,那就是典型的零和博弈,状态可以递推。定义 dp[i][j] 表示当前先手在区间 [i, j] 上能拿到的最大净胜分,转移时考虑取左边还是右边,对手会同样最优地应对。
当然,如果游戏规则允许某种对称操作,可能存在贪心结论,直接判断奇偶性就能出答案。考场上最忌讳一上来就写搜索,先手算几个小数据把规律找到,往往能省很多时间。
代码框架
下面给出一个 C++ 实现骨架。核心逻辑需要根据题目具体的操作规则来填充,这里用区间 DP 的情况做一个示意:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; ++i) cin >> a[i];
// dp[i][j] 表示区间 [i, j] 上先手能拿到的最大净胜分
vector<vector<int>> dp(n, vector<int>(n, 0));
// 按区间长度从小到大计算
for (int len = 1; len <= n; ++len) {
for (int i = 0; i + len - 1 < n; ++i) {
int j = i + len - 1;
if (len == ) {
dp[i][j] = a[i];
} {
dp[i][j] = (a[i] - dp[i][j], a[j] - dp[i][j]);
}
}
}
(dp[][n] > ) cout << << endl;
(dp[][n] < ) cout << << endl;
cout << << endl;
;
}


