分级【构造新序列,使得单调序列与原序列差值的绝对值最小】【先排序,在DP】

分级

题意

image-20201009180149478

思路

先处理单调递增的情况:构造一个新序列b,使得abs(b[i]-a[i]) 和最小。

结论为:b序列为a序列中排好序的组合。即:先把a序列排序,然后a序列中课重复按照顺序组成b序列。

这些序列取最小值。

定义f[i] [j]: 构造的b序列中前i 个,并且最后一个为a[j]的序列

状态转移:可以枚举b序列的前i-1个,最后一个为aj之前的数。这里三重循环,然后可以拿前缀和优化为二重循环。

image-20201009190637383

这是单调递增的情况,其中每个点在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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值