传送门

这是一篇研究潮学、用于颓废的题解。

其实这题并不难,但是思维很巧妙。

一个显而易见的思路就是设$f(i,j)​$为前$i​$个数都满足递增且第$i​$个数为$j​$的最小代价。就有转移方程$f(i,j)=min\{f(i-1,k)+abs(a_i-j) \}(k\le j)​$。不过值域$1e9​$,无论空间还是时间都受不了。

把这个做法写出来并记录方案,用瞪眼法就会发现修改后的数一定是原数列的某个数。

重新设$f(i,j)​$为前$i​$个数都满足递增且第$i​$个数是原数列中第$j​$大的数的最小代价。先离散化,和原来一样转移,时间复杂度为$O(n^3)​$。然后这玩意可以直接前缀最小值优化成$O(n^2)​$。

写完后一交。。。过了。

A了再来证明

数(X)学(J)归(B)纳(扯)法:

只有一个数时显然保留原值是最优的。

假设前$k$个值已经满足递增了,考虑第$k+1$个值的处理方案:

这里假设$k=3$:

如上图,潮爷用第一种方案,一定是把自己变得和最强的一样强代价最小;用第二种方案,一定是把比他强的人变得和潮爷一样代价最小。

因为第一个数是原数列的数,所以后面的都还是原数列的数。

证完了!

($wavwing$说这个结论显而易见,看来是我太蒻了)

(其实这个题还有$O(n\log n)$的做法,也是基于这个结论,懒得写了

(顺便说一句洛咕数据未免太水我忘了写递减的情况结果过了?)

(所以我并不打算把递减的补上

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>

#define maxn 2005
#define inf 0x3f3f3f3f

using namespace std;

inline int read(){
    int x=0,y=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return y?-x:x;
}
int f[maxn][maxn],a[maxn],dis[maxn];
int main(){
    int n=read(),len;
    for(register int i=1;i<=n;++i)
        dis[i]=a[i]=read();
    sort(dis+1,dis+1+n);
    len=unique(dis+1,dis+1+n)-dis-1;//离散化
    memset(f,0x3f,sizeof f);
    for(register int i=1;i<=len;++i)
        f[0][i]=0;
    for(register int i=1;i<=n;++i)
        for(register int j=1;j<=len;++j)
            f[i][j]=min(f[i-1][j]+abs(a[i]-dis[j]),f[i][j-1]);//前缀最小值
    printf("%d\n",f[n][len]);
}