题意:
给你一个个数为n的序列,序列的每个数可以随意加减,其加减值算作成本,问你把序列变成不严格的单调上升序列的最小成本。
思路:
先对原序列a离散化,即排序去重存在数组b中,dp[i][j]表示把序列a的前i个数的最大值(即a[i])变成b[j]所积累的总成本,dp转移式为:
dp[i][j] = mi + abs(a[i] - b[j]),
其中mi = min(mi, dp[i - 1][1 ~ j])。
为什么只要把a[i]变成b[j](1 < j < cnt, cnt为a排序去重后剩下的个数)就可以了呢,而不是变成b[j - 1] ~ b[j]之间的数,仔细想想(因为要求是变成不严格单调数列,所以相邻两个数可以相等)。
code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 2e3 + 5;
const long long inf = 1e13 + 5;
int a[maxn], b[maxn];
long long dp[maxn][maxn];
void init(int n){
for(int i = 0; i <= n; i++)
dp[0][i] = 0;
}
int main(){
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
b[i] = a[i];
}
init(n);
//离散化
sort(b + 1, b + 1 + n);
int cnt = unique(b + 1, b + 1 + n) - b - 1;
for(int i = 1; i <= n; i++){
long long mi = inf;
for(int j = 1; j <= cnt; j++){
mi = min(mi, dp[i - 1][j]); //b[j]肯定大于b[j]前面的b[],保证了序列是单调上升的。
dp[i][j] = mi + abs(a[i] - b[j]);
}
}
long long ans = inf;
for(int i = 1; i <= cnt; i++)
ans = min(ans, dp[n][i]);
printf("%lld\n", ans);
}