这个题要往DP上想(左偏树什么的也不会)
首先要知道这样一个结论:一定存在一个最优解,使得整理后的数组中不存在整理前数组中不存在的数,亦即:对于每个Bi,一定存在j,使得Bi=Aj。
可以这么想,在做调整时,一定是这么做的,先选出连续的三个数abc,
假设a<=c,那么要组成递增序列,
如果b>=a && b<=c,则不需调整;
如果b<a,则最小的调整可以是把b变成a;
如果b>c,则最小的调整可以是把b变成c.
所以归纳可知上面结论成立。
dp[i][j] 表示考虑前i个元素,最后元素为序列中 第j小元素的最优解,a[]数组存原始数组,b[]是对a从小到大排序。
dp[i][j] = MIN(dp[i-1][k]) + abs(a[i]-b[j]), (0<k<=j)
这样总时间复杂度是n^3,空间复杂度是n^2.
可以把状态转移时间优化到o(1),滚动数组把空间优化到o(n).
具体可以参考代码
#include<cstdio>
#include<stdlib.h>
#include<cstring>
#include<algorithm>
#include<math.h>
using namespace std;
int n,ans;
int a[2010],b[2010],dps[2010],m[2010];
int Min(int a,int b){
return a>b?b:a;
}
void dp(){
int i,j;
memset(m,0,sizeof(m));
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
dps[j]=m[j]+abs(a[i]-b[j]);
if(j>1)
m[j]=Min(dps[j],m[j-1]);
else
m[j]=dps[j];
}
ans=dps[1];
for(i=1;i<=n;i++)
ans=Min(ans,dps[i]);
}
int main(){
int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
dp();
int ans1=ans;
for(i=1;i<=n/2;i++){
int tem=b[i];
b[i]=b[n-i+1];
b[n-i+1]=tem;
}
dp();
int ans2=ans;
printf("%d\n",Min(ans1,ans2));
}