UVA10891 Game of Sum

区间dp

2.UVA10891 Game of Sum

题目描述

有一个长度为 nn 的整数序列,两个游戏者 AABB 轮流取数,AA 先取。每次玩家只能从左端或者右端取任意数量的数,但不能两边都取。所有数都被取走视为游戏结束,然后统计每个人取走的数之和,作为各自的得分。两个人采取的策略都是让自己得分尽可能高,并且两个人都很机智,求 AA 得分 - BB 得分后的结果。

输入格式

输入包含多组数据,每组数据第一行为正整数 n(1n100)n(1\leq n\leq 100) ,第二行为给定的整数序列,输入结束标志是 n=0n=0

输出格式

对于每组数据,输出 AABB 都采取最优策略下,AA 的得分B-B 的得分。

题目分析

因为取数字的操作只能在头和尾进行,那么其在任意时候都是一个连续的序列,记dp[l][r]dp[l][r]为先手在l,rl,r这个子序列中获得的最大分数,那么很容易想到n3n^3暴力区间dp,状态转移方程为dp[l][r]=sum[l][r]min(dp[l][l+1],dp[l][l+2]....dp[l][r],dp[r][r],dp[r1][r],dp[r2][r]...dp[l][r])dp[l][r]=sum[l][r]-min(dp[l][l+1],dp[l][l+2]....dp[l][r],dp[r][r],dp[r-1][r],dp[r-2][r]...dp[l][r])答案为dp[1][n]+(sum[n]dp[1][n])dp[1][n]+(sum[n]-dp[1][n]),考虑如何写n2n^2,观察到状态转移方程中有两坨东西,这坨东西可以在状态转移的时候记录在另一个数组里,然后就完成了优化,直接变成O(n2)O(n^2)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//
// Created by mrx on 2022/9/24.
//
#include <iostream>
#include <algorithm>
#include <vector>
#include <array>

using ll = long long;

int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);

int n;
while (std::cin >> n && n) {
std::vector<int> a(n + 1);
for (int i = 1; i <= n; ++i)std::cin >> a[i];
std::vector<int> sum(n + 1);
for (int i = 1; i <= n; ++i)sum[i] = sum[i - 1] + a[i];
std::vector<std::vector<int>> dp(n + 1, std::vector<int>(n + 1, 0));
std::vector<int> lmin(n + 1, 0x3f3f3f3f), rmin(n + 1, 0x3f3f3f3f);

for (int len = 1; len <= n; ++len) {
for (int l = 1; l + len - 1 <= n; ++l) {
int r = l + len - 1;
dp[l][r] = sum[r] - sum[l - 1] - std::min({0, lmin[l], rmin[r]});
lmin[l] = std::min(lmin[l], dp[l][r]);
rmin[r] = std::min(rmin[r], dp[l][r]);
}
}
std::cout << 2 * dp[1][n] - sum[n] << '\n';
}
return 0;
}

UVA10891 Game of Sum
https://mrxyan6.github.io/2022/09/24/UVA10891/
作者
mrx
发布于
2022年9月24日
许可协议