来自学长的快乐AK题——Day3 C

6 篇文章 0 订阅
3 篇文章 0 订阅

C——线段树+DP

Description

有n个木桩依次排列,第i个木桩的高度为hi,其上的果冻数量为xi。

开始的时候可以选择站在任意一个木桩上,每次跳跃不限长度而且只能从左向右跳跃,但只能跳到高度与当前所站高度差绝对值小于等于m的柱子上。

问最多能拿到多少个果冻。

最终不一定要落在最后一个木桩上。

思路

由于题目中提示异常明显:只能从左向右跳跃,因此这道题显然为DP题。

设fi表示到了高度i能获得的最大果冻数。考虑任意木桩i,能转移到f[h[i]]的状态范围为f[h[i]-m~h[i]+m],我们显然要从这其中选择最大的值进行转移。

考虑用线段树维护最大值f[k],转移方程为f[h[i]]=max(f[h[i]],f[k]+x[i]),转移后的值再插入线段树中更新当前最大值。

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
const int N=1e7;
int n,m,h[N],a[N],f[N],tree[N],ans,maxn;//f[i]表示高度为i时最多的果冻数量 
void update(int k,int x,int y,int p,int val)//单点修改 
{
	if(x==y)
	{
		tree[k]=val;
		return;
	}
	int mid=(x+y)>>1;
	if(p<=mid) update(k<<1,x,mid,p,val);
	else update(k<<1|1,mid+1,y,p,val);
	tree[k]=max(tree[k<<1],tree[k<<1|1]);
}
int query(int k,int x,int y,int a,int b)//区间查询最大值 
{
	if(x==a&&y==b) return tree[k];
	int mid=(x+y)>>1;
	if(b<=mid) return query(k<<1,x,mid,a,b);
	else if(a>mid) return query(k<<1|1,mid+1,y,a,b);
	else return max(query(k<<1,x,mid,a,mid),query(k<<1|1,mid+1,y,mid+1,b));
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	scanf("%d%d",&h[i],&a[i]),maxn=max(maxn,h[i]);
	maxn+=m;//高度的最大值为最大的h[i]+m 
	for(int i=1;i<=n;i++)
	{
		//查询可以转移到f[h[i]的最大的状态
		f[h[i]]=max(f[h[i]],query(1,0,maxn,max(0,h[i]-m),h[i]+m)+a[i]);
		//更新h[i]位置上的数据 
		update(1,0,maxn,h[i],f[h[i]]);
	}
	for(int i=0;i<=maxn;i++)
	ans=max(ans,f[i]);
	printf("%d",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值