题意:
给你一个长度为n的数组,让你把它分成n段,每一段的价值是这一段内的最大值减最小值,数组的价值为每段价值的和。
求当k = 1, 2, 3, … , n的时候,总价值分别是多少。
题解:
设
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k]表示将前
i
i
i个数分成
j
j
j段,
k
k
k表示状态。我们分析可以得到当前一共可能有
4
4
4种状态,分别为在第
j
j
j段的时候
0
(
我
还
没
有
选
到
最
大
值
和
最
小
值
)
0(我还没有选到最大值和最小值)
0(我还没有选到最大值和最小值),
1
(
选
到
了
最
大
值
)
1(选到了最大值)
1(选到了最大值),
2
(
选
到
了
最
小
值
2(选到了最小值
2(选到了最小值)和
3
(
两
个
数
都
选
到
了
)
3(两个数都选到了)
3(两个数都选到了)。
然后我们继续分析发现
n
n
n的范围是
1
e
4
1e4
1e4,有爆内存的风险,并且我的当前状态只和上一个状态有关,所以可以用滚动数组来优化。具体看代码吧。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int n;
int a[N], dp[2][N][4];
void solve()
{
cin >> n;
for (int i = 1; i <= n; i ++ ) cin >> a[i];
memset(dp, -0x3f, sizeof dp);
int f = 0;
dp[1][0][3] = 0;
for (int i = 1; i <= n; i ++ )
{
for (int j = 1; j <= n; j ++ )
{
dp[f][j][0] = dp[f ^ 1][j - 1][3];
dp[f][j][1] = dp[f ^ 1][j - 1][3] + a[i];
dp[f][j][2] = dp[f ^ 1][j - 1][3] - a[i];
dp[f][j][3] = dp[f ^ 1][j - 1][3];
dp[f][j][0] = max(dp[f][j][0], dp[f ^ 1][j][0]);
dp[f][j][1] = max(dp[f][j][1], dp[f ^ 1][j][0] + a[i]);
dp[f][j][1] = max(dp[f][j][1], dp[f ^ 1][j][1]);
dp[f][j][2] = max(dp[f][j][2], dp[f ^ 1][j][2]);
dp[f][j][2] = max(dp[f][j][2], dp[f ^ 1][j][0] - a[i]);
dp[f][j][3] = max(dp[f][j][3], dp[f ^ 1][j][3]);
dp[f][j][3] = max(dp[f][j][3], dp[f ^ 1][j][1] - a[i]);
dp[f][j][3] = max(dp[f][j][3], dp[f ^ 1][j][2] + a[i]);
}
f ^= 1;
}
f ^= 1;
for (int i = 1; i <= n; i ++ )
cout << dp[f][i][3] << '\n';
}
int main()
{
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}
总结:
在做题的时候我只是单纯的将当前的数看成是否要从这里新开一段,导致没有一点思路,看了答案才知道应该是将这个时候都有什么状态表示出来,而不是强硬地去凑结果,这里要重点反思。做题经验不够,应该继续加油。