-
分级
题目
提交记录
讨论
题解
视频讲解
给定长度为N的序列A,构造一个长度为N的序列B,满足:
1、B非严格单调,即B1≤B2≤…≤BN
或B1≥B2≥…≥BN。
2、最小化 S=∑Ni=1|Ai−Bi|
。
只需要求出这个最小值S。
输入格式
第一行包含一个整数N。
接下来N行,每行包含一个整数Ai
。
输出格式
输出一个整数,表示最小S值。
数据范围
1≤N≤2000
,
1≤|Ai|≤109
输入样例:
7
1
3
2
4
5
3
9
输出样例:
3
看了闫学灿的DP分析法有了很大的启发。
前置知识
必然有一个满足条件的B序列,其中的数都在A中出现过。
算法 DP
预处理出B数组为A数组的有序版
1 状态
**f[i,j]**表示与A[1…i]匹配的B[1…i]的结尾是B[j]时S的最小值。
2集合
要求出f[i,j],所依赖的集合
f[i-1][1…j]
**
3 方程
f[i,j]=min(f[i,j],f[i-1,k]+abs(a[i]-b[j])) (1<=k<=j)
#include<bits/stdc++.h>
using namespace std;
int n,a[2001],b[2001];
int f[2001][2001];
int main(){
// freopen("in","r",stdin);
memset(f,0x3f,sizeof(f));
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
for(int i=0;i<=n;i++)
f[0][i]=0;
for(int i=1;i<=n;i++){
int val=f[i-1][0];
for(int j=1;j<=n;j++){
val=min(val,f[i-1][j]);
f[i][j]=min(f[i][j],val+abs(b[j]-a[i]));
}
}
int ans=1<<30;
for(int i=1;i<=n;i++)
ans=min(ans,f[n][i]);
printf("%d\n",ans);
return 0;
}