萌新6:临场发挥(区间dp)

题目描述

小x和室友总共 nnn 人,组团去打一款游戏,总共有 nnn 台电脑供他们使用,一人一台,最开始,第 iii 个人使用第 iii 台电脑。

小x评估了每个人的能力值和临场发挥值。

第 iii 个人的能力值为 aia_iai​。

而他们的临场发挥值由能力值和他们所使用的电脑决定。

小x和他的室友喜欢换来换去。

他们惊奇的发现:如果第 iii 个人从第 xxx 台电脑换到了第 yyy 台电脑,那么第 iii 个人的临场发挥值会增加 ∣x−y∣∗ai|x-y|*a_i∣x−y∣∗ai​。

现在他们可以重新任意分配一次电脑。

小x想知道他们的临场发挥值最多会增加多少?

输入描述:

第一行一个整数 nnn (2≤n≤2000)(2 \leq n \leq 2000)(2≤n≤2000)。

第二行 nnn 个整数 a1,a2,……,ana_1,a_2,……,a_na1​,a2​,……,an​ (1≤ai≤109)(1 \leq a_i \leq 10^9)(1≤ai​≤109)。

输出描述:

一个整数,表示 临场发挥值 最大增加的数量

示例1

输入

复制4 1 3 4 2

4
1 3 4 2

输出

复制20

20

说明

假设第 iii 个人的位置为 cic_ici​,从 [1,2,3,4][1,2,3,4][1,2,3,4] 更换为 [3,4,1,2][3,4,1,2][3,4,1,2],临场发挥值增加: 1×∣1−3∣+3×∣2−4∣+4×∣3−1∣+2×∣4−2∣=201 \times |1-3|+3 \times |2-4|+4 \times |3-1|+2 \times |4-2|=201×∣1−3∣+3×∣2−4∣+4×∣3−1∣+2×∣4−2∣=20

示例2

输入

复制6 8 6 9 1 2 1

6
8 6 9 1 2 1

输出

复制85

85

做法

首先要看出来一个贪心的小结论。就是就是能力值大的,应该放在两边,反之放中间。

#include<bits/stdc++.h>
#define int long long
using namespace std;

int n;
pair<int,int> a[2010];
int dp[2010][2010];

signed main(){

    scanf("%lld",&n);
    for(int i=1;i<=n;i++) {
        int b;
        scanf("%lld",&b);
        a[i]={b,i};
    }

    sort(a+1,a+1+n);

    for(int i=1;i<=n;i++){//枚举区间长度和每次取出的数
        int b=a[i].first,id=a[i].second;
        for(int l=1;l<=n-i+1;l++){//枚举每个长度i的区间,求最大值
            int r=l+i-1;
            dp[l][r]=max(dp[l][r-1]+abs(id-r)*b,dp[l+1][r]+abs(id-l)*b);//b放右边和左边
        }
    }

    cout<<dp[1][n];

}

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值