分级
给定序列A 构造序列非严格单调的B 使\(\sum|a_i-b_i|\)最小
搜索->dp 关键在引理:
b中的数一定在a中都出现过
所以可以离散化考虑 只考虑出现过的数
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=2010;
const int INF=0x3f3f3f3f;
int read()
{
int x=0,f=0,c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return f?-x:x;
}
int n,tot;
int a[N],b[N],f[N][N];
//f(i,j)=min{f(i-1,k)+|ai-j|} 0<=k<=j
int main()
{
n=read();
for(int i=1;i<=n;i++) b[i]=a[i]=read();
sort(b+1,b+n+1);
tot=unique(b+1,b+n+1)-(b+1);
for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+tot+1,a[i])-b;
for(int i=1;i<=n;i++) f[1][i]=abs(b[a[1]]-b[i]);
for(int i=2;i<=n;i++)
{
int minn=INF;
for(int j=1;j<=tot;j++)
{
minn=min(minn,f[i-1][j]);
f[i][j]=minn+abs(b[a[i]]-b[j]);
}
}
int ret=INF;
for(int i=1;i<=tot;i++) ret=min(ret,f[n][i]);
for(int i=2;i<=n;i++)
{
int minn=INF;
for(int j=tot;j>=1;j--)
{
minn=min(minn,f[i-1][j]);
f[i][j]=minn+abs(b[a[i]]-b[j]);
}
}
for(int i=1;i<=tot;i++) ret=min(ret,f[n][i]);
printf("%d\n",ret);
return 0;
}
思考题:
把A改成单调不下降的,最少需要修改:
A的总长度-A的最长 不下降子序列
把A改成单调上升的:
\(B_i-A_i-i\) 用吧的长度减去最长不下降子序列长度
原因: A中的位置不一定足够满足严格上升这一个条件 由于两个数之间最少相差i 因此把i减去 就可以让条件相互转化
已经出现过的 可以考虑用离散化来优化这个过程

浙公网安备 33010602011771号