hdu 4258(斜率优化DP)

题目大意:将n个升序数字序列,分成几组连续的序列 ,每一组的所得值,等于最右边的num2减去最左边 的num1,的平方+c即(numi-numj)^2+c

解题报告 人:GHQ(SpringWater)

分析可得:(dp[j2]-dp[j1]+num[j2+1]*num[j2+1]-num[j1+1]*num[j1+1])/(2(num[j2+1]-num[j1+1]))《=num[i]时,j2比j1更优,可知这是一个凹曲线斜率优化;

i<j<k时且k(i,j)>=k(j,k)时,那么j是可以去掉的。

1.当 k(j,k)《=num[i]时,j没 k优,可去 j

2.当 k(j,k)>=num[i]时,则k(i,j)》=num[i],i比j优秀,可去j!


自己默思:1,:为什么当前队列左边相邻的k(l,l+1) 第一个满足>num[i]时,即l比l+1优,则l比右边的所有 都优,因为l和右边的组合斜率是增加的,l+1同样优于l+2,

由传递性可得,第一次l为最优,

2:为什么当前i总用和相邻的(r-1,r)和(r,i)比较即可确定是否删除r,因为当k(r,i)>=k(r,r-1)则k(r,i)大于在队列里所有任意 组合 的 斜率!能确保 k(r,i)是最大的 斜率。

也就 保证了,斜率递增!

当>=num[i]时为凸曲线斜率优化!

hdu4258

#include<stdio.h>
#define MAXN 1000005
int que[10000];
__int64 num[MAXN],dp[MAXN];
double k(int j1,int j2)
{
	return (double)(dp[j2]-dp[j1]+num[j2+1]*num[j2+1]-num[j1+1]*num[j1+1])/(double)(2.0*(num[j2+1]-num[j1+1]));
}
int main()
{
	int n, i, l, r;
	__int64 c;
	while(scanf("%d%I64d",&n,&c) && (n || c))
	{
		for(i = 1; i <= n; i++)
			scanf("%I64d",&num[i]);
		dp[0] = 0;
		dp[1]=c;
		que[l = 0] = 0;
		que[r = 1] = 1;
		for(i = 2; i <= n; i++)
		{
			while((l < r)&&k(que[l],que[l+1])<=(double)num[i])++l;
			dp[i]=dp[que[l]]+c+(num[i]-num[que[l]+1])*(num[i]-num[que[l]+1]);
			while((l < r)&&k(que[r],i)<=k(que[r-1],que[r]))--r;
			que[++r] = i;
		}
		printf("%I64d\n",dp[n]);
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值