分级
题意
思路
先处理单调递增的情况:构造一个新序列b,使得abs(b[i]-a[i]) 和最小。
结论为:b序列为a序列中排好序的组合。即:先把a序列排序,然后a序列中课重复按照顺序组成b序列。
这些序列取最小值。
定义f[i] [j]: 构造的b序列中前i 个,并且最后一个为a[j]的序列
状态转移:可以枚举b序列的前i-1个,最后一个为aj之前的数。这里三重循环,然后可以拿前缀和优化为二重循环。
这是单调递增的情况,其中每个点在a序列中。
单调递减的情况,就是把横轴翻转一下,然后求递增。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mst(s,_s) memset(s, _s, sizeof(s))
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;
const int N = 2e3+100;
int T,n,m;
int a[N],b[N];
int f[N][N];
int res=INF;
void work()
{
for(int i=1;i<=n;i++) b[i]=a[i];
sort(b+1,b+1+n);
for(int i=1;i<=n;i++)
{
int temp=INF;
for(int j=1;j<=n;j++)
{
temp=min(temp,f[i-1][j] + abs(a[i]-b[j]));
f[i][j]=temp;
}
}
for(int i=1;i<=n;i++) res=min(res,f[n][i]);
}
int main() {
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
work();
reverse(a+1,a+n+1);
work();
//cout<<res<<endl;
printf("%d",res);
return 0;
}