ZLOJ练习51E & [BZOJ2364]城市美化
written on 2022-07-27
乍一看以为是贪心,但是贪心正确性又不能保证,随便交了一发只有 \(20pts\)。但是事实上这题只是一道简单 dp。。
状态设计显然,设 \(f_{i,j}\) 表示前 \(i\) 个房屋,第 \(i\) 个高度为 \(j\) 的最小花费。然后转移亦显然,\(f_{i,j}=f_{i-1,k}+...\)
这样会超时,考虑优化,优化也蛮显然的,记录一个前缀一个后缀的最小值,这样的话直接转移即可,时间复杂度 \(O(nh)\),其中 \(h\leq 1000\)。能过。
注意细节,每一个高度都要更新到,要不然会出现答案错误。
#include<bits/stdc++.h>
#define N 50005
#define M 1005
using namespace std;
typedef long long ll;
int n,c;
ll mn[M],MN[M],f[2][M];
int a[N];
int main()
{
scanf("%d%d",&n,&c);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
memset(f[1],0x3f,sizeof(f[1]));
memset(mn,0x3f,sizeof(mn)),memset(MN,0x3f,sizeof(MN));
for(int i=a[1];i<=1000;i++) f[1][i]=1ll*(i-a[1])*(i-a[1]);
for(int i=1;i<=1000;i++) mn[i]=min(mn[i-1],f[1][i]-1ll*c*i);
for(int i=1000;i>=1;i--) MN[i]=min(MN[i+1],f[1][i]+1ll*c*i);
for(int i=2;i<=n;i++)
{
memset(f[i&1],0x3f,sizeof(f[i&1]));
for(int j=a[i];j<=1000;j++) f[i&1][j]=1ll*(j-a[i])*(j-a[i])+min(1ll*c*j+mn[j],MN[j]-1ll*c*j);
memset(mn,0x3f,sizeof(mn)),memset(MN,0x3f,sizeof(MN));
for(int j=1;j<=1000;j++) mn[j]=min(mn[j-1],f[i&1][j]-1ll*c*j);
for(int j=1000;j>=1;j--) MN[j]=min(MN[j+1],f[i&1][j]+1ll*c*j);
}
ll ans=1e18;
for(int i=a[n];i<=1000;i++) ans=min(ans,f[n&1][i]);
printf("%lld\n",ans);
}