Atcoder Beginner Contest 266 problem D 题解

Atcoder Beginner Contest 266 problem D 题解


题目链接:点我

题目大意

一条路上有 5 5 5个格子,分别是 0 , 1 , 2 , 3 , 4 0,1,2,3,4 0,1,2,3,4。一共有 N N N条蛇,每条蛇有三个属性: t i , x i , w i t_i,x_i,w_i ti,xi,wi分别表示这条蛇的出现的时间,出现的位置和这条蛇的价值。

现在,一个人要来抓蛇。他初始在 0 0 0的位置。每一秒钟,这个人可以向前一格,向后一格,或者在原地不动。第 i i i条蛇会在 t i t_i ti的时间从 x i x_i xi的格子钻出来。如果此时这个人恰好在 x i x_i xi的位置,那么他就可以抓住这条蛇,并获得它的价值 w i w_i wi。问这个人可以获得的总价值最大是多少?

样例输入1

3
1 0 100
3 3 10
5 4 1

样例输出1

101

样例解释1

  • 0 0 0号格子等待 1 1 1秒钟,然后在时间 1 1 1抓住 1 1 1号蛇,得到价值 100 100 100
  • 前往 4 4 4号格子,在时间 5 5 5抓住 3 3 3号蛇,得到价值 1 1 1

总价值为 101 101 101,这是最大的了。

样例输入2

3
1 4 1
2 4 1
3 4 1

样例输出2

0

样例输入3

10
1 4 602436426
2 1 623690081
3 3 262703497
4 4 628894325
5 3 450968417
6 1 161735902
7 1 707723857
8 2 802329211
9 0 317063340
10 2 125660016

样例输出3

2978279323

数据范围

  • 1 ≤ N ≤ 1 0 5 1 \leq N \leq 10^5 1N105
  • 0 < t 1 < t 2 < . . . < t N ≤ 1 0 5 0 < t_1 < t_2 < ... <t_N \leq 10^5 0<t1<t2<...<tN105
  • 0 ≤ x i ≤ 4 0 \leq x_i \leq 4 0xi4
  • 1 ≤ w i ≤ 1 0 9 1 \leq w_i \leq 10^9 1wi109
  • 所有输入均为整型数。

解析

本蒟蒻看到这道题,第一反应是贪心,并且分了两种情况来贪:

  1. 根据时间贪心
  2. 根据价值贪心

不过,本蒟蒻很快就 Hack 掉了贪心,证明如下:

1.如果根据时间贪心,那么这组数据就不正确:

2
4 54 1
5 0 100

根据时间来看,我们应该走到 4 4 4号格子得到价值 1 1 1。但实际上,我们如果一直待着不动,那么我们会得到价值 100 100 100。显然后者更优,但并不满足时间贪心的条件。

2.如果根据价值贪心,那么这组数据就不正确:

3
4 4 5
6 1 2
7 0 4

根据价值贪心的话,我们会选择走到 4 4 4号格子得到价值 5 5 5,然后就得不到更多价值了。但实际上,若果我们只走到 1 1 1号格子上并等待到 6 6 6秒,然后第 7 7 7秒再走到 0 0 0号格子,这样可以抓住两条蛇得到价值 6 6 6。显然后者更优,但并不满足价值贪心的条件。

至此,贪心全面崩盘。

贪心不行,那肯定就是 d p dp dp来凑了嘛!我们观察到时间 t t t是严格递增的,给出的格子数目又很小,于是,我们可以定义一下状态:

f [ i ] [ j ] f[i][j] f[i][j]表示第 i i i秒时这个人在 j j j号格子时能获得的最大价值数。

由于这个人每秒可以选择做三件事,于是 f f f数组可以这样转移: f [ i ] [ j ] = m a x ( f [ i − 1 ] [ j − 1 ] , f [ i − 1 ] [ j ] , f [ i − 1 ] [ j + 1 ] ) f[i][j]=max(f[i-1][j-1],f[i-1][j],f[i-1][j+1]) f[i][j]=max(f[i1][j1],f[i1][j],f[i1][j+1])

如果说在时间 i i i,格子 j j j上刚好有一条蛇出现的话,那么就要加上这条蛇的价值: f [ i ] [ j ] + = a [ i d ] f[i][j]+=a[id] f[i][j]+=a[id] i d id id表示 i i i时间出现的是第几条蛇。可以用二分求得。


代码实现

#include<iostream>
#include<cstring>
using namespace std;
const int N=1e5+5;
int n;
int t[N],x[N],w[N];
long long ans,f[N][6];//注意数据范围,要用long long存储答案
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>t[i]>>x[i]>>w[i];
    memset(f,-0x3f,sizeof f);
    f[0][0]=0;//初始化。0时间时在0号格子,什么也没做,所得到的的价值是0
    for(int i=1;i<=t[n];i++){
        int res=lower_bound(t+1,t+n+1,i)-t,X,W;
        if(t[res]!=i) X=233;
        else X=x[res],W=w[res];//用二分找到当前时间是否有蛇
        for(int j=0;j<=4;j++){
            f[i][j]=max(f[i-1][j+1],max(f[i-1][j-1],f[i-1][j]));
            if(X==j) f[i][j]+=W;//如果有蛇,加上价值
        }
    }
    for(int i=0;i<=4;i++) ans=max(ans,f[t[n]][i]);//对五个格子都要扫一遍,找到最大值
    cout<<ans;
}

完结撒花~~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值