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[能够到i的木桩j]+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(i−m,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;
}