ICPC2022网络赛第二场

B Non-decreasing Array 暴力动态规划

推荐一个大佬的博客:大佬的讲解

题意

emm,大家来看题解应该都明白题意,就不写了。

思路(区间dp)

f [ i ] [ j ] f[i][j] f[i][j]的两个状态分别表示为从开头到以 i i i 为结尾的删除 j j j 个数的最大值。所以我们就可以得出最后的结果就是 f [ n ] [ p o s ] f[n][pos] f[n][pos],pos的值后面会说。
首先我们怎么找出所有的以 i i i 结尾的所有的情况呢?这时候我们可以在纸上画一下:
在这里插入图片描述
通过不断调整起点的位置( i i i 的位置是终点)就可以得到所有的情况了。具体的操作就是不断改变k的长度。长度里面的全部删除需要k次操作,我们一共要删除j次,所以就是:

f [ i − k − 1 ] [ j − k ] + ( a [ r ] − a [ l ] ) ∗ ( a [ r ] − a [ l ] ) ; f[i - k - 1][j - k] + (a[r] - a[l]) * (a[r] - a[l]); f[ik1][jk]+(a[r]a[l])(a[r]a[l]);

最后在结果上我们要观察结果的情况,我们可以得到删除一次但是跨越的距离是2,比如:

	1 2 3 4 5,第一次的操作是 1 2 5 5,删掉3,把4变成5,所以就相当于
1 2 5,删掉了两个数的最大值的情况。
代码:
#include <bits/stdc++.h>

using namespace std;

const int N = 111;
#define int long long

int n;
int a[N];
int f[N][N]; // 第i位 删除j次 但是保留i位置 的最大值

int calc(int l, int r) {
    return (a[r] - a[l]) * (a[r] - a[l]);
}

signed main() 
{
    cin >> n;
    for(int i = 1; i <= n; i ++ ) cin >> a[i];
    
    for(int i = 1; i <= n; i ++ ) 
        for(int j = 0; j <= i - 2; j ++ ) // 删除多少个数,小于等于2就是开头和结尾不能删除
            for(int k = 0; k <= j; k ++ ) 
            {
                int pos = i - k - 1; // 删除[pos + 1, i - 1]的区间:[i - k + 1, i - 1] // k是长度
                f[i][j] = max(f[i][j], f[pos][j - k] + calc(pos, i));
            }
    
    for(int i = 1; i <= n; i ++ ) 
    {
        // 因为能过操作两次所以删除乘2,就是删除1次但我可以用距离为2的数字,2次就是距离为4
        if(i * 2 > n - 2) cout << f[n][n - 2] << endl;
        else cout << f[n][2 * i] << endl;
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值