感谢原作者。
题意
给一组正整数,让你对每个数进行增减使得最终形成一个不严格单调序列,并保证代价最小(每个数字增减绝对值的和)
方法
考虑不严格递增数列。
状态:f[i][j] 表示第i个数为第j小的最小代价,同时保证1到i不严格单增。
转移方程:f[i][j]=min(f[i-1][1:j])+delta
此题可以用滚动数组。
注意:在获取f[i-1][1:j]时,不用加第三层循环。具体做法见代码。同时,因为这样不得使遍历顺序从小到大,滚动数组要开两条。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAXN=2000+5;
int n;
long long int num[MAXN];
long long int nums[MAXN];
long long int f[2][MAXN];
long long int ans=(1<<30);
long long int aabs(long long int a){
return a>0?a:-a;
}
void init(){
memset(f,0,sizeof(f));
cin>>n;
for(int i=1;i<=n;i++){
scanf("%lld",&num[i]);
nums[i]=num[i];
}
sort(nums+1,nums+1+n);
}
int main(){
init();
for(int i=1;i<=n;i++)
f[1][i]=aabs(num[1]-nums[i]);
for(int i=2;i<=n;i++){
long long int tmin=(1<<30);
for(int j=1;j<=n;j++){
tmin=min(tmin,f[(i+1)%2][j]);
f[i%2][j]=tmin+aabs(num[i]-nums[j]);
}
}
for(int i=1;i<=n;i++)
ans=min(ans,f[n%2][i]);
cout<<ans<<endl;
return 0;
}
posted on
浙公网安备 33010602011771号