牛客小b白月赛40 B-跳跳跳(区间dp)

传送门

不知道为什么标题连小白都不能起

题目描述

在这里插入图片描述

输入描述

在这里插入图片描述

输出描述

在这里插入图片描述
输入样例1

3
1 1 1

输出样例1

6

样例1说明

在这里插入图片描述
输入样例2

3
1 2 3

输出样例2

14

样例2说明

在这里插入图片描述


区间 dp 的板子题,对于环形问题,首先开两倍长度断环成链,使环形问题变为直线问题。本题中,虽然可以自由选择向左或向右进行移动,但由于需要选择尚未被跳过的位置的限制,因此仅需要考虑对于某个点,上一步是从左边来还是右边来,同时注意每一步权值 i 的存在。

本题以四个点举例,可以发现断环成链后,以 2 出发并从两个方向走完所有点的方案分别为从 2 到 5 和从 6 到 3。为了简化,本题以状态 f [ l ][ r ] 表示在不考虑方向情况下的端点,即该状态即可表示从 l 走到 r,也可表示从 r 走到 l,保证 l ≤ r。可以发现在该样例中,以 2 为起点但往不同方向行走是由两种状态表示的,而与其中 f [ 2 ][ 5 ] 共享一种状态的是 1 - 4 - 3 - 2 ,即对调起点和终点。
请添加图片描述

因此对于每一种状态,仅需要比较该状态是由左向右还是由右向左的收益更大,更大的即为以该状态的两个维度为起点和终点时区间内的最大值。

状态转移方程:

f [ l ] [ r ] = m a x ( f [ l ] [ r − 1 ] + l e n ∗ a [ r ] , f [ l + 1 ] [ r ] + l e n ∗ a [ l ] ) ; f[l][r] = max(f[l][r - 1] + len * a[r], f[l + 1][r] + len * a[l]); f[l][r]=max(f[l][r1]+lena[r],f[l+1][r]+lena[l]);

其中,l、r 为某一区间的左右端点,并分为从 l 由左向右跳到 r 点和从 r 从右向左跳到 l 点两种情况进行讨论,并加上对应步数的贡献,其中 len 标记的为步数。

参考代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll f[4005][4005]={
    
    0};
ll a[4005];

int main(){
    
    
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
    
    
        cin >> a[i];
        f[i][i] = f[i + n][i + n] = a[i + n] = a[i];
    }

    ll res = 0;
    for (int len = 2; len <= n; ++len) {
    
    
        for (int l = 1; l + len - 1 <= n + n; ++l) {
    
    
            int r = l + len - 1;
            f[l][r] = max(f[l][r - 1] + len * a[r], f[l + 1][r] + len * a[l]);
            res = max(res, f[l][r]);
        }
    }
    cout << res;
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/laysan/article/details/121232488