题意:
有一堆数, 两个人轮流取, 只能从最左边开始选择, 假设上一个人选了k 个牌, 那么下一个人只能选择k 或 k + 1 张牌。 第一个人得分为A, 第二个人得分为B, 求A- B, 每个人的策略都想使自己得分尽可能的高。
思路:
是UVA 10891 的变形把。
我们令dp[i][j] 表示从i 位置开始选择, 能选j 个牌的最大分数差值。
那么直接根据j 来转移即可。
总共两种选择, 要么选j 个, 要么选j + 1个, 处理个前缀和即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 20000 + 1;
const int inf = 0x3f3f3f3f;
int dp[maxn][200];
bool vis[maxn][200];
int a[maxn], n;
int sum[maxn], ks;
int dfs(int pos, int k){
int& ans = dp[pos][k];
if (vis[pos][k] == 1) return ans;
vis[pos][k] = 1;
if (pos > n){
return ans = 0;
}
if (pos + k - 1 > n){
return ans = 0;
}
ans = -inf;
int lak = pos + k - 1;
int lak1 = pos + k;
if (lak <= n){
ans = max(ans, sum[lak] - sum[pos - 1] - dfs(lak + 1, k));
}
if (lak1 <= n){
ans = max(ans, sum[lak+1] - sum[pos - 1] - dfs(lak1 + 1, k + 1));
}
return ans;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d", &n);
memset(vis,0,sizeof vis);
for (int i = 1; i <= n; ++i){
scanf("%d", &a[i]);
sum[i] = sum[i-1] + a[i];
}
printf("%d\n", dfs(1, 1));
}
return 0;
}
1 3 1 3 2
4