题目大意:
n个数字弄成非递增或者非递减的最小花费。
题目思路:
首先我们想要改某座山的话,一定会改成是这群山里的某个的高度,如果改成一个中间的数值,那不就亏了吗,假如之前的山已经改好了,要改第 i 座山,如果这个比上一个小,为什么不把他改成这个呢,如果比后一个大,为啥不改成后边那个呢,(这里的后边,指的不是后边具体的那一座山,是指后边的最优情况)。
本来想的是dp[i][j]表示第i个数改成 j 使得前i个递增的最小花费,但是这个第二维太大了,但是根据上边那一段话我们可以知道,第二维只需要把所有数据离散化掉就可以了,dp[i][j] 表示第i个数改成 第 j 个数使得前i个递增的最小花费。
b为离散化后数组,a为原来的数组
dp[i][j] = abs( a[i] - b[j] ) + min( dp[i-1][ k ] ) 1 <= k <= j
同理,非递增的话,我们把数组反过来,再次跑一边就可以了。
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int MAXN = 1e5+5;
ll dp[2005][2005],dp2[2005][2005];
ll a[MAXN],b[MAXN],c[MAXN];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
c[n-i+1] = a[i];
b[i] = a[i];
}
sort(b+1,b+1+n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dp[i][j] = 1ll<<62;
dp2[i][j] = 1ll<<62;
}
}
for(int i=1;i<=n;i++){
dp[0][i] = 0;
dp2[0][i] = 0;
}
for(int i=1;i<=n;i++){
ll Min = 1ll<<62;
ll Min2 = 1ll<<62;
for(int j=1;j<=n;j++){
Min = min(Min,dp[i-1][j]);
Min2 = min(Min,dp2[i-1][j]);
dp[i][j] = min(dp[i][j],abs(a[i]-b[j]) + Min);
dp2[i][j] = min(dp2[i][j],abs(c[i]-b[j])+Min);
}
}
ll ans = 1ll<<62;
for(int i=1;i<=n;i++){
//cout<<dp[n][i]<<" * ";
ans = min(ans,dp[n][i]);
ans = min(ans,dp2[n][i]);
}
cout<<ans<<endl;
}