bzoj 4723: [POI2017]Flappy Bird 贪心

题意

《飞扬的小鸟》是一款风靡的小游戏。在游戏中,小鸟一开始位于(0,0)处,它的目标是飞到横坐标为X的某个位置上。每一秒,你可以选择点击屏幕,那么小鸟会从(x,y)飞到(x+1,y+1),或者不点击,那么小鸟会飞到(x+1,y-1)。在游戏中还有n个障碍物,用三元组(x[i],a[i],b[i])描述,表示在直线x=x[i]上,y<=a[i]或者y>=b[i]的部分都是障碍物,碰到或者擦边都算游戏失败。请求出小鸟从(0,0)飞到目的地最少需要点击多少次屏幕。
0<=n<=500000

分析

考虑从后往前模拟,对于奇数坐标和偶数坐标分别维护可到达的区间,然后再从前往后做一遍,每次找到能到达的所有位置中坐标最小的一个走就好了。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

typedef long long LL;

const int N=500005;

int n,m,l0[N],r0[N],l1[N],r1[N];
struct data{int x,u,v;}a[N];

int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

bool odd(int x)
{
    return abs(x)&1;
}

int main()
{
    n=read();m=read();
    for (int i=1;i<=n;i++) a[i].x=read(),a[i].u=read()+1,a[i].v=read()-1;
    a[0].u=-1;a[0].v=1;
    if (odd(a[n].u)) l1[n]=a[n].u,l0[n]=a[n].u+1;
    else l0[n]=a[n].u,l1[n]=a[n].u+1;
    if (odd(a[n].v)) r1[n]=a[n].v,r0[n]=a[n].v-1;
    else r0[n]=a[n].v,r1[n]=a[n].v-1;
    for (int i=n-1;i>=0;i--)
    {
        int d=a[i+1].x-a[i].x;
        l0[i]=l0[i+1];r0[i]=r0[i+1];l1[i]=l1[i+1];r1[i]=r1[i+1];
        if (odd(d)) std::swap(r0[i],r1[i]),std::swap(l0[i],l1[i]);
        l0[i]-=d;l1[i]-=d;r0[i]+=d;r1[i]+=d;
        int l=a[i].u,r=a[i].v;
        l+=(!odd(l));r-=(!odd(r));
        l1[i]=std::max(l1[i],l);r1[i]=std::min(r1[i],r);
        l=a[i].u;r=a[i].v;
        l+=odd(l);r-=odd(r);
        l0[i]=std::max(l0[i],l);r0[i]=std::min(r0[i],r);
    }
    LL ans=0;int x=0;
    for (int i=0;i<n;i++)
    {
        int d=a[i+1].x-a[i].x,y;
        if (odd(x)&&odd(d)||!odd(x)&&!odd(d))
        {
            int l=std::max(x-d,l0[i+1]),r=std::min(x+d,r0[i+1]);
            if (l>r) {puts("NIE");return 0;}
            y=l;
        }
        else
        {
            int l=std::max(x-d,l1[i+1]),r=std::min(x+d,r1[i+1]);
            if (l>r) {puts("NIE");return 0;}
            y=l;
        }
        if (y>=x) ans+=y-x+(d-y+x)/2;
        else ans+=(d-x+y)/2;
        x=y;
    }
    printf("%lld",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值