题解 P2893 【[USACO08FEB]Making the Grade G】
Martian148 · · 题解
Link
P2893 [USACO08FEB]Making the Grade G
Solve
这道题实际上是有
因为数据很大,所以我们不能直接拿数值
这里我们有一个结论:
满足答案最小化的前提下,一定存在一种构造序列
B 的方案,使得B 中的数值都在A 中出现过。
证明:
数学归纳法。命题
设结论对
当
否则,要么令
证毕.
有了这个结论,就很简单了
我们定义
显然转移方程就比较简单了
但是这个转移方程直接推是
我们发现
这种维护前面某个状态的最小值来降低维度的方法是可以转移的,如果前面某个量是线性增长的,就可以用记一下前面的最优答案方便转移。
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=2005;
int N,ans=1<<30,a[maxn],b[maxn],F[maxn][maxn],Min[maxn][maxn];
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
int main(){
freopen("P2893.in","r",stdin);
freopen("P2893.out","w",stdout);
N=read();
for(int i=1;i<=N;i++)a[i]=read(),b[i]=a[i];
sort(b+1,b+1+N);
memset(Min,63,sizeof Min);
memset(Min[0],0,sizeof Min[0]);
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++){
F[i][j]=Min[i-1][j]+abs(a[i]-b[j]);
Min[i][j]=min(F[i][j],Min[i][j-1]);
}
for(int i=1;i<=N;i++)ans=min(ans,F[N][i]);
for(int i=1;i<=N/2;i++)swap(b[i],b[N-i+1]);
memset(F,0,sizeof F);
memset(Min,63,sizeof Min);
memset(Min[0],0,sizeof Min[0]);
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++){
F[i][j]=Min[i-1][j]+abs(a[i]-b[j]);
Min[i][j]=min(F[i][j],Min[i][j-1]);
}
for(int i=1;i<=N;i++)ans=min(ans,F[N][i]);
printf("%d\n",ans);
return 0;
}