链接:https://vjudge.net/problem/POJ-3666
思路:(本题其实可以只用求递增,数据出的有失误)一直在思考怎么表示状态,猜到了最后结果肯定都是原来的几个数,所以我们可以考虑离散化,考虑到后一位是否要变取决于前一位的最大值,那么我们用dp[i][j]表示枚举到第i个数,且最后一位为第j大的数,转移的话dp[i][j] = min(dp[i-1][1,2,3,....j-1]) +abs(a[i]-c[j]),其实不需要枚举k,用一个变量在递推的时候维护最小值就可以了,好好思考一下离散化+dp的操作。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2010;
ll a[maxn];
ll c[maxn];
int n;
ll dp[maxn][maxn];
int main(){
while(~scanf("%d",&n)){
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++)scanf("%lld",&a[i]),c[i] = a[i];
memset(dp,0,sizeof(dp));
sort(c+1,c+n+1);
int len = unique(c+1,c+n+1)-c-1;
for(int i=1;i<=n;i++){
//递推时维护最小值
long long minv = dp[i-1][1];
for(int j=1;j<=len;j++){
minv = min(minv,dp[i-1][j]);
dp[i][j] = minv+abs(a[i]-c[j]);
}
}
ll res = 1e18;
for(int i=1;i<=len;i++)res = min(res,dp[n][i]);
printf("%lld\n",res);
}
return 0;
}