传送门
做这题需要进阶指南上提到的一个引理:在满足S最小化的前提下,一定存在一种构造序列B的方案,使得B中的数值都在A中出现过。证明略。
我们可以从这个引理入手设计状态,设dp[i][j]表示将a[i]变为j需要的最小cost,且此时i之前的dp值都已经求好。将数组离散化并放入num数组。状态转移方程如下
dp[i][j] = min(dp[i][j], dp[i-1][k]+abs(a[i]-num[j])
,k是j之前的数。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int dp[2005][2005]; //dp[i][j]表示把a[i]变成j需要的cost
int a[2005], num[2005];
int main(){
memset(dp, 0x3f3f3f3f, sizeof(dp));
int n;
cin >> n;
for(int i = 1; i <= n; ++i){
cin >> a[i];
num[i] = a[i];
}
sort(num+1, num+1+n);
int lim = unique(num+1, num+1+n) - num;
dp[0][0] = 0;
for(int i = 1; i <= n; ++i){
int minn = dp[i-1][0];
for(int j = 1; j < lim; ++j){
minn = min(minn, dp[i-1][j]);
dp[i][j] = minn + abs(a[i]-num[j]);
}
}
int ans = 0x3f3f3f3f;
for(int i = 1; i < lim; ++i){
if(dp[n][i] < ans) ans = dp[n][i];
}
cout << ans << endl;
return 0;
}