【BZOJ 1592】[Usaco2008 Feb]Making the Grade 路面修整 dp优化之转移变状态

时间:2021-01-01 00:41:18

我们感性可证离散(不离散没法做),于是我们就有了状态转移的思路(我们只考虑单不减另一个同理),f[i][j]到了第i块高度为j的最小话费,于是我们就可以发现f[i][j]=Min(f[i-1][k])+|a[i]-j|(k<=j),于是我们的思路就去了各种数据结构…….然后我们发现对于这些转移就是在记录小于等于,那么我们直接带状态里体现这一点就可以了,而不是在转移的时候,我们f[i][j]表示到了第i个点小于等于j的高度的最小花费,这样我们就n^2了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 2010
using namespace std;
inline int read()
{
register int sum=;register char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')sum=(sum<<)+(sum<<)+ch-'',ch=getchar();
return sum;
}
int a[N],f[N][N],ans,n,pos[N],len,Hash[N];
int comp(const int x,const int y){
return a[x]<a[y];
}
inline int Min(int x,int y){
return x<y?x:y;
}
inline int Abs(int x){
return x<?-x:x;
}
inline int get_Min(){
memset(f,0x7f,sizeof(f));register int ans=0x7fffffff;
for(register int i=;i<=len;i++)f[][i]=Min(f[][i-],Abs(Hash[i]-Hash[a[]]));
for(register int i=;i<=n;i++)
for(register int j=;j<=len;j++)
f[i][j]=Min(f[i][j-],f[i-][j]+Abs(Hash[j]-Hash[a[i]]));
for(register int i=;i<=len;i++)ans=Min(ans,f[n][i]);
return ans;
}
inline int get_Max(){
memset(f,0x7f,sizeof(f));register int ans=0x7fffffff;
for(register int i=;i<=len;i++)f[][i]=Min(f[][i+],Abs(Hash[i]-Hash[a[]]));
for(register int i=;i<=n;i++)
for(register int j=len;j>;j--)
f[i][j]=Min(f[i][j+],f[i-][j]+Abs(Hash[j]-Hash[a[i]]));
for(register int i=;i<=len;i++)ans=Min(ans,f[n][i]);
return ans;
}
int main(){
n=read();for(register int i=;i<=n;i++)a[i]=read(),pos[i]=i;
sort(pos+,pos+n+,comp);
for(register int i=;i<=n;i++)
if(i==||a[pos[i]]!=a[pos[i-]])Hash[++len]=a[pos[i]],a[pos[i]]=len;
else a[pos[i]]=len;
printf("%d",Min(get_Min(),get_Max()));
}