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);
}
posted @ 2022-07-31 22:41  Freshair_qprt  阅读(28)  评论(0编辑  收藏  举报