2020-2021 ICPC银川站 B - The Great Wall(动态规划)

题意:

给你一个长度为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;
}
总结:

在做题的时候我只是单纯的将当前的数看成是否要从这里新开一段,导致没有一点思路,看了答案才知道应该是将这个时候都有什么状态表示出来,而不是强硬地去凑结果,这里要重点反思。做题经验不够,应该继续加油。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值