资源限制
内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s
问题描述
逗志芃又一次面临了危机。逗志芃的妹子是个聪明绝顶的人,相比之下逗志芃就很菜了。现在她妹子要和他玩一个游戏,这个游戏是这样的:一共有n个数(n是偶数)写成一行,然后两个人轮流取数,每次只能从最前面或者最后面取走一个数,全部取完则游戏结束,之后每个人取走的数的和就是每个人的得分。由于逗志芃妹子很厉害,但他又不想输,所以只能找到你了,你要告诉他最多可以得到多少分。(注意,妹子智商是maxlongint所以是不会犯错的,每次的策略必然最优,而且逗志芃是先手)
输入格式
第一行一个数n,表示有n个数。
第二行就是进行游戏的n个数。
输出格式
一个数,最高得分
样例输入
2
10 20
样例输出
20
数据规模和约定
例:0<n,m<=1000,每个数不超过10000 。
思路
首先,我们需要初始化二维数组
dp
。对角线(即i=j
的情况)上的元素是初始化的基础,因为当只剩下一个数字时,先手玩家显然会选择这个数字,所以dp[i][i] = nums[i]
。接下来,我们使用两层循环,从后往前遍历所有可能的子数组。由于先手玩家总是可以选择取走第一个数或最后一个数,因此,当剩余数字为从第i个到第j个时,先手玩家可以获得的最大得分就是
nums[i] - dp[i+1][j]
和nums[j] - dp[i][j-1]
中的较大值。这里的dp[i+1][j]
和dp[i][j-1]
是已经计算过的子问题的解,代表的是当先手玩家取走第i个数或第j个数后,剩余数字为从第i+1个到第j个或从第i个到第j-1个时,先手玩家可以获得的最大得分。
最后,
(sum(nums) + dp[0][n-1]) // 2
是先手玩家在整个游戏中可以得到的最大得分。这是因为sum(nums)
是所有数字的总和,dp[0][n-1]
是先手玩家可以获得的最大得分,所以(sum(nums) + dp[0][n-1]) // 2
就是先手玩家最后的得分。
举例
例如,假设有4个数字,5, 3, 7, 10。在第一步,先手玩家有两种选择:取5或者取10。如果取5,后手玩家会在3和10之间选择较大的10,然后先手玩家会在3和7之间选择较大的7,最后只剩下3,由后手玩家取走。这种情况下,先手玩家得分为5+7=12分。如果取10,后手玩家会在5和7之间选择较大的7,然后先手玩家只能取5,最后剩下3,由后手玩家取走。这种情况下,先手玩家得分为10+5=15分。所以,先手玩家应该选择取10,这样可以得到最大得分。
代码
def max_score(nums):
n = len(nums)
dp = [[0] * n for _ in range(n)]
for i in range(n):
dp[i][i] = nums[i]
for i in range(n-2, -1, -1):
for j in range(i+1, n):
dp[i][j] = max(nums[i] - dp[i+1][j], nums[j] - dp[i][j-1])
return (sum(nums) + dp[0][n-1]) // 2
n = int(input().strip())
nums = list(map(int, input().strip().split()))
print(max_score(nums))