题意
有一座城市,城市中有n(1≤n≤5000)n(1≤n≤5000)座山,是从左到右按一行排列的,每座山有一个已知的高度hh,一座房子能在第座山上建造,当且仅当hi−1<hihi−1<hi且hi>hi+1hi>hi+1,现在这座城市的市长想对这些山进行修整,他们可以花一天的时间将某一座山的高度减掉11。现在,对于所有的,他们想知道最少需要多少天可以建造出kk幢房子(除了调整山的高度外,其他时间一律不计)。
分析
首先我们可以考虑DP,用表示现在DP到第ii座山,座山里有jj幢可以建房子,状态为的最小天数。当k=0k=0时表示第ii座山和第座山都不用来建房子;当k=1k=1时表示第ii座山不建房子,第座山建房子;当k=2k=2时表示第ii座山建房子,第座山建房子,然后就可以进行转移了。不过要注意,这里我们将第ii座山设为建房子的那座山时,对第座山的影响放在第i+1i+1位进行计算,这样防止有重复计算等麻烦出现。在表示完状态后就可以轻易地想出DP转移的式子了。
f[i][j][0]=min(f[i−1][j][0],f[i−1][j][1])f[i][j][0]=min(f[i−1][j][0],f[i−1][j][1])如果这一座山和前一座山都不是山峰的转移。
f[i][j][1]=f[i−1][j][2]+max(0,h[i]−h[i−1]+1)f[i][j][1]=f[i−1][j][2]+max(0,h[i]−h[i−1]+1)这里是计算第i−1i−1座建房子是对第ii座山的影响。
这里是分两种情况考虑,当第i−2i−2座山也被拿来建房子时,要考虑第i−2i−2座山对第i−1i−1座山的影响与第ii座山拿来建房子是对第座山的影响。如果第i−2i−2座山不拿来建房子,那就不用考虑了。
最后对于所有的kk,只要在里取minmin就好了。
Code
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
const int maxn=5005;
int n,h[maxn],f[maxn][maxn][3];
int main() {
memset(f,0x3f,sizeof f);
read(n);
for(int i=1;i<=n;++i)
read(h[i]);
f[0][0][0]=0;
for(int i=1;i<=n;++i) {
for(int j=0;j<=i;++j) {
f[i][j][0]=min(f[i-1][j][0],f[i-1][j][1]);
f[i][j][1]=f[i-1][j][2]+max(0,h[i]-h[i-1]+1);
if(j)
f[i][j][2]=min(f[i-1][j-1][0]+max(0,h[i-1]-h[i]+1),f[i-1][j-1][1]+max(0,min(h[i-2]-1,h[i-1])-h[i]+1));
}
}
for(int i=1;i<=(n+1)/2;++i)
printf("%d ",min(f[n][i][2],min(f[n][i][0],f[n][i][1])));
}