#P1899. 第3题-玩游戏
-
1000ms
Tried: 114
Accepted: 3
Difficulty: 8
所属公司 :
美团
时间 :2024年8月17日
-
算法标签>动态规划
第3题-玩游戏
思路:动态规划
以下思路考场能AC,但是有点问题。
定义dp[i][j][0]代表a[i,...,j]中连续子段的最小值
定义dp[i][j][1]代表a[i,...,j]中连续子段的最大值
可以采用二维循环求出dp数组。
之后枚举小乖选择哪个子段,然后计算这个子段情况下小坏所能达到的最小贡献,并取最大值即为最终答案。
注意博弈思想,二者均是选择最优的方案,并且是小乖先手。当小乖操作完毕后,无论是什么结果,小坏的最优操作方案均为:
- k>0,选取最小的连续子段和,并将该子段乘k
- k<0,选取最大的连续子段和,并将该子段乘k
而对于小乖来说,如果在小坏操作完后,其不能达到理想的最大值,那么小乖就应当选择另外一种操作,以达到理想的最大值。
代码
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int length, multiplier;
length = scanner.nextInt();
multiplier = scanner.nextInt();
long[] elements = new long[length + 1];
long[] prefixSum = new long[length + 1];
long[][][] dp = new long[length + 1][length + 1][2];
for (int i = 1; i <= length; i++) {
elements[i] = scanner.nextLong();
prefixSum[i] = prefixSum[i - 1] + elements[i];
}
for (int segment = 1; segment <= length; segment++) {
for (int start = 1; start + segment - 1 <= length; start++) {
int end = start + segment - 1;
if (segment == 1) {
dp[start][end][0] = dp[start][end][1] = elements[start];
} else {
dp[start][end][0] = Math.min(Math.min(dp[start + 1][end][0], dp[start][end - 1][0]), calculateSum(prefixSum, start, end));
dp[start][end][1] = Math.max(Math.max(dp[start + 1][end][1], dp[start][end - 1][1]), calculateSum(prefixSum, start, end));
}
}
}
long maximumValue = Long.MIN_VALUE;
for (int i = 1; i <= length; i++) {
for (int j = i; j <= length; j++) {
long product1 = calculateSum(prefixSum, i, j) * (multiplier - 1);
long product2 = Math.min(dp[i][j][0] * multiplier * (multiplier - 1), dp[i][j][1] * multiplier * (multiplier - 1));
if (i != 1) {
product2 = Math.min(product2, Math.min(dp[1][i - 1][0] * (multiplier - 1), dp[1][i - 1][1] * (multiplier - 1)));
}
if (j != length) {
product2 = Math.min(product2, Math.min(dp[j + 1][length][0] * (multiplier - 1), dp[j + 1][length][1] * (multiplier - 1)));
}
maximumValue = Math.max(maximumValue, product1 + product2);
}
}
System.out.println(calculateSum(prefixSum, 1, length) + maximumValue);
}
private static long calculateSum(long[] prefixSum, int left, int right) {
return prefixSum[right] - prefixSum[left - 1];
}
}
小乖和小坏在玩一个游戏,游戏中有一个长度为 n 的数组a1,a2,...,an 和一个固定的整数k。游戏规则如下,双方都会执行最优策略:
第一步,小乖选择一个非空的区间 [l,r],将这个区间中的所有数字都乘上 k。
第二步, 小坏选择一个非空的区间 [l,r], 将这个区间中的所有数字都乘上 k。
记sum=i=1∑nai 小坏想让sum尽可能小,小乖想让sum尽可能大,你需要求出最后 sum 的值。
输入描述
第一行输入两个整数 n 和 k(10−5≤k≤105,1≤n≤1000;−105≤ai≤105),代表数组长度和固定的整数。
第二行输入 n 个整数 a1,a2,...,an, (−105≤ai≤105)代表数组。
输出描述
在一行上输出一个整数表示答案。
示例 1
输入
6 2
-1 -2 -3 1 2 3
输出
0
说明
小乖会选择区间[4,6],数组变成{−1,−2,−3,2,4,6};
小坏会选择区间[1,3],数组变成{−2,−4,−6,2,4,6};
数组总和为 0。