2021-08-11 SSL 模拟赛 T3

2021-08-11 SSL 模拟赛 T3

啊仍然没有标题。
在这里插入图片描述

题目大意:

有一堆木桩,你可以从任意一个开始从左往右跳,不限距离,有一些木桩去不到,有一些去得到。到达一个木桩后你可以拿走上面的果冻,你可以随时在其中一个木桩停止下来。问你最多可以拿到多少个果冻?

思路:

这题是比较明显的动态规划。
我一开始想到的状态转移方程是 f [ i ] = m a x ( f [ i ] , f [ 能 够 到 i 的 木 桩 j ] + x [ i ] ) , f[i]=max(f[i],f[能够到i的木桩j]+x[i]), f[i]=max(f[i]f[ij]+x[i]),f[i] 表示到达 i 时能够得到的最大值。
然后我悲催的发现要预处理出任意两个木桩之间的连通状态,时间复杂度 O ( n 2 ) O(n^2) O(n2)炸到不知道哪里去了 妥妥的超时。
那么我们考虑设 f [ i ] f[i] f[i] 表示高度为 i i i 处能够获得的果冻最大值,那么可以向 i i i 转移的区间就是
[ m a x ( i − m , 1 ) , i + m ] [max(i-m,1),i+m] [max(im,1),i+m],然后我们在这个区间中找到最大的 f [ k ] f[k] f[k] 向 i 转移。
这就需要我们动态维护区间最大值,使用线段树即可。
最后答案为 m a x ( f [ 1 ] , f [ 2 ] , ⋅ ⋅ ⋅ f [ m a x ( h [ 1 , 2 , ⋅ ⋅ ⋅ n ] ) ) max(f[1],f[2],···f[max(h[1,2,···n])) max(f[1],f[2],f[max(h[1,2,n]))

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<vector>
#define r register
#define rep(i,x,y) for(r ll i=x;i<=y;++i)
#define per(i,x,y) for(r ll i=x;i>=y;--i)
using namespace std;
typedef long long ll;
const ll V=1e6+2000;
ll h[V],f[V],x[V],n,m,tree[V<<4],maxn,ans;
void update(ll x)
{
	tree[x]=max(tree[x<<1],tree[x<<1|1]);
}
//void build(ll now,ll le,ll ri)
//{
//	if(le==ri)
//	{
//		tree[now]=f[le];
//		return ;
//	}
//	ll mid=le+ri>>1;
//	build(now<<1,le,mid);
//	build(now<<1|1,mid+1,ri);
//	update(now);
//}
void add(ll now,ll le,ll ri,ll p,ll val)
{
	if(le==ri)
	{
		tree[now]=max(tree[now],val);
		return ;
	}
	ll mid=le+ri>>1;
	if(p<=mid) add(now<<1,le,mid,p,val);
	else add(now<<1|1,mid+1,ri,p,val);
	update(now);
}
ll ask(ll now,ll le,ll ri,ll x,ll y)
{
	if(le>=x&&ri<=y) return tree[now];
	ll mid=le+ri>>1,res=0;
	if(x<=mid) res=max(res,ask(now<<1,le,mid,x,y));
	if(mid+1<=y) res=max(res,ask(now<<1|1,mid+1,ri,x,y));
	return res;
}
int main()
{
	scanf("%lld%lld",&n,&m);
	rep(i,1,n) 
	{
		scanf("%lld%lld",&h[i],&x[i]);
	//	f[h[i]]=x[i];
		maxn=max(maxn,h[i]);
	}
	f[h[1]]=x[1];
	add(1,1,maxn,h[1],x[1]);
	rep(i,2,n)
	{
		ll L=max(h[i]-m,1ll),R=h[i]+m;
		ll j=ask(1,1,maxn,L,R);
		f[h[i]]=max(f[h[i]],j+x[i]);
		add(1,1,maxn,h[i],f[h[i]]);
	}
	rep(i,1,maxn) ans=max(ans,f[i]);
	cout<<ans;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值