题解 P6304 【[eJOI2018]山】
DP裸题,考虑怎么设状态
设
表示前
具体实现看代码:
#include<cstdio>
#include<cctype>
#define maxn 5555
inline int read(){
int r=0,f=0;
char c;
while(!isdigit(c=getchar()))f|=(c=='-');
while(isdigit(c))r=(r<<1)+(r<<3)+(c^48),c=getchar();
return f?-r:r;
}
inline int min(int a,int b){
return a<b?a:b;
}
inline int val(int x){
return x<0?0:x;
}
int n,a[maxn],f[maxn][maxn][2][2];
int main(){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
f[i][0][1][0]=1e9+10;
for(int j=1;j<=((n+1)>>1);j++)
for(int x=0;x<2;x++)
for(int y=0;y<2;y++)
f[i][j][x][y]=1e9+10;
}
f[1][0][0][0]=f[1][1][0][1]=0;
a[0]=1e9;
for(int i=2;i<=n;i++)
for(int j=1;j<=((i+1)>>1);j++){
f[i][j][0][0]=min(f[i-1][j][1][0],f[i-1][j][0][0]);
//这条转移显然
f[i][j][1][0]=f[i-1][j][0][1]+val(a[i]-a[i-1]+1);
//因为不能挨着建,所以[1][0]只能由[0][1]转移而来
f[i][j][0][1]=min(f[i-1][j-1][0][0]+val(a[i-1]-a[i]+1),f[i-1][j-1][1][0]+val(min(a[i-2]-1,a[i-1])-a[i]+1));
//注意,如果是由[1][0]转移过来的话,那么第i-1座山已经小于a[i-2]了,不需要算两遍
}
for(int i=1;i<=((n+1)>>1);i++){
int ans=1e9+10;
for(int x=0;x<2;x++)
for(int y=0;y<2;y++)
ans=min(ans,f[n][i][x][y]);
printf("%d ",ans);
}
return 0;
}