AcWing 1511:笨鸟

【题目来源】
https://www.acwing.com/problem/content/1513/

【题目描述】
小王特别喜欢玩 flappy birds,但是他比较菜,所以向大家寻求帮助,游戏规则大家都懂,
每一秒如果点击屏幕,小鸟会从 (x,y) 飞到 (x+1,y+1);如果不点击屏幕,小鸟则会飞到 (x+1,y−1)
笨鸟
初始坐标 (0,0),要飞到横坐标为 X 的地方,纵坐标不做要求。
沿途有一些
障碍,用 (x0,a,b) 的形式给出,表示在横坐标为 x0 的地方 y≤ay≥b 的地方都是障碍,碰到或者擦边都算游戏失败。
也就是说,小鸟通过此横坐标时纵坐标必须在 (a,b) 这个范围内,且
纵坐标不等于 a 或 b
如果这只笨鸟根本没有办法飞到终点横坐标,则输出”Stupid bird!”(不包含引号)。
否则输出通过每个障碍以及终点横坐标时所需要点击屏幕的最少次数。
注意:在考虑通过某个障碍所需最少点击次数时,不用考虑此操作对通过后面障碍物的影响以及是否能够确保通关。

【输入格式】
第一行两个整数 n,X。
接下来 n 行,每行三个整数 (xi,ai,bi),含义见题目描述。

【输出格式】
若笨鸟飞不到终点,输出“Stupid bird!”(不含引号) 。
否则输出包含 n+1 行。
前 n 行,每行一个整数,表示通过每个障碍时所需最少的点击次数。
最后一行,表示到达终点横坐标时所需的最少点击次数。

【数据范围】
0≤n≤5×10^5
1≤X≤10^9
0<xi<X
−10^9≤ai<bi≤10^9
x_i<x_{i+1}

【输入样例】
4 11
4 1 4
7 -1 2
8 -1 3
9 0 2

【输出样例】
3
4
4
5
5

【算法分析】
● 本题题意可参见原型游戏 flappy bird:
https://flappybird.io/
● 求解本题,请参考如下示意图。特别要注意 b 和 a 在图中的位置以及 up 及 down 的含义。显然,up=up+x-lastdown=down-(x-last)

● 不管障碍物距 0 点的距离 x 是偶数还是奇数,能够到达的 y 值均是离散的且相差 2。之所以离散,是因为小鸟的坐标是按秒更新的。且,若障碍物距 0 点的距离 x 值是偶数/奇数,则能够到达的离散 y 值也是偶数/奇数。

据上,便有了判断奇偶性的要求。代码如下所示。

if((x&1) != (a&1)) a++;
if((x&1) != (b&1)) b--;

即,若 x 与 a 的奇偶性不一致,则 a++;若 x 与 b 的奇偶性不一致,则 b++。
(注意:a、b 在示意图中的位置)

此代码用位运算 & 判断奇偶性。即,
若 x&1 为真,则 x 为奇数;否则,x 为偶数

● 通过每个障碍时所需最少的点击次数
设 x 是障碍物距 0 点的距离,y 是在 x 处时“笨鸟”通过障碍物的坐标,hit 是点击次数,则可知 hit-(x-hit)=y,也即 hit=(x+y)/2。若要使 hit 最小,则取 y 的最小值 down,故得通过每个障碍时所需最少的点击次数为 
hit=(x+down)/2。此处的 hit 对应于下面代码中的 imin[i]。

【算法代码】

#include <bits/stdc++.h>
using namespace std;

const int N=5e5+5;
int imin[N]; //minimum number of per step
bool flag=true;
int up,down; //scope
int last; //Coordinates of the last obstacle

int main() {
    int n,X;
    cin>>n>>X;
    for(int i=1; i<=n; i++) {
        int x,a,b;
        cin>>x>>a>>b;
        up=up+x-last;
        down=down-(x-last);

        //The range that the bird can fly
        a++,b--; //can't reach to a and b
        if((x&1) != (a&1)) a++;
        if((x&1) != (b&1)) b--;
        up=min(up,b);
        down=max(down,a);

        //Update the bird interval
        if(up<down) {
            flag=false;
            break;
        }
        imin[i]=(x+down)/2;
        last=x;
    }

    if(!flag) cout<<"Stupid bird!"<<endl;
    else {
        for(int i=1; i<=n; i++) cout<<imin[i]<<endl;
        cout<<imin[n]<<endl;
    }

    return 0;
}

/*
in:
4 11
4 1 4
7 -1 2
8 -1 3
9 0 2

out:
3
4
4
5
5
*/




【参考文献】
https://www.luogu.com.cn/problem/P1941
https://www.acwing.com/solution/content/88484/
https://www.acwing.com/solution/content/23727/



 

  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值