POJ3336 Making the Grade

思路:DP

提交:1次

题解:

最开始我们可以想到,分两种序列都做一遍。
先来证明一个结论:
存在一种构造,使 \(B\) 中的数都在 \(A\) 中出现过,且这样不劣。
(目的是为了转化暂时看起来虚无缥缈的DP)
显然一个数成立,考虑 \(B\) 的前 \(k-1\) 项,向后插入一个数 \(B_k\)
\(B_{k-1}\leq A_k\) ,我们直接递增插入,否则 \(B_k=B_{k-1}\) ,亦或者存在一个 \(j\) ,使 \(B_j,B_{j+1},\cdots,B_{k}\) 相等,且代价更小(中位数的性质)。
这样我们考虑DP:
\(f[i][j]\)\(i\) 个数,最后一个数为 \(j\) (注意 \(j\) 是离散化后的位置)
\(f[i][j]=\min_{0 \leq k \leq j}(f[i-1][k]+|j-A_i|)\)
注意到对于一个 \(i\) 决策集合是在单调扩大的,所以可以用一个变量记录前面的最小值,直接转移。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
	register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
	do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
} const int N=2010;
int n,m,a[N],b[N];
int f[N][N],ans=1e+9;
inline void main() {
	n=g(); for(R i=1;i<=n;++i) b[i]=a[i]=g();
	sort(b+1,b+n+1); R m=unique(b+1,b+n+1)-b-1; 
	memset(f,0x3f,sizeof f); f[0][0]=0;
	for(R i=1;i<=n;++i) {
		R mn=f[i-1][0];
		for(R j=1;j<=m;++j) {
			mn=min(mn,f[i-1][j]);
			f[i][j]=mn+abs(a[i]-b[j]);
		}
	} for(R i=1;i<=m;++i) ans=min(ans,f[n][i]);
	printf("%d\n",ans);
}
} signed main() {Luitaryi::main(); return 0;}

2019.09.18
58

posted @ 2019-09-18 21:46  LuitaryiJack  阅读(139)  评论(0编辑  收藏  举报