这是一篇dp的题解.题目是acwing 273.分级.
题目描述很简单哈.
题目:给定长度为N的序列A,构造一个长度为N的序列B,满足:
1、B非严格单调,即B1≤B2≤…≤BN或B1≥B2≥…≥BN。
2、最小化 S=∑Ni=1|Ai−Bi|。
只需要求出这个最小值S。
输入格式
第一行包含一个整数N。
接下来N行,每行包含一个整数Ai。
输出格式
输出一个整数,表示最小S值。
这个怎么做呢?首先我们得知道符合条件的Bi必定有一组是全部属于Ai的,证明很简单,我们把Ai排序变成Ci,假设我们当前有几组不在Ci,位于
Ci~Ci+1因为中间数变成它们并不影响其他数取值,假如当前这段的Ai比Ci+1大的为x,比Ci小的为y,那么当x=y怎么把这段移动都是不变的,而一旦大于小于则一定要移动.
有了这个性质就比较好dp了.因为有递增这个性质,我们设dp[i][j]为前i个,最后一个Bi为Cj,使得这样最小.
至于转移就是上一个最小且dp[i-1]转移过来的,因为我这里既然要取j当最后一个,那么后面的dp[i-1][>j]就不可取了,且前面取最小就好了QAQ.
递减也是一样的.
代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N=2e3+5;
int dpa[N][N],dpb[N][N];
int a[N],b[N],c[N];
int main()
{
    int n,ans=2e9;
    cin>>n;
    for(int i=1;i<=n;i++)   {cin>>a[i];b[i]=a[i];c[i]=a[i];}
    sort(b+1,b+n+1);
    sort(c+1,c+n+1);
    reverse(c+1,c+1+n);
    for(int i=1;i<=n;i++)
    {
        int res=2e9;
        for(int j=1;j<=n;j++)
        {
            res=min(res,dpa[i-1][j]);
            dpa[i][j]=res+abs(a[i]-b[j]);
        }
    }
    for(int i=1;i<=n;i++)
    {
        int res=2e9;
        for(int j=1;j<=n;j++)
        {
            res=min(res,dpb[i-1][j]);
            dpb[i][j]=res+abs(a[i]-c[j]);
        }
    }
    for(int i=1;i<=n;i++) ans=min(ans,min(dpa[n][i],dpb[n][i]));
    cout<<ans<<endl;
    return 0;
}