【BZOJ】4723 [POI2017]Flappy Bird-dp/找规律

传送门:bzoj4723


题解

看到此题,本蒟蒻去重温了一下fb…(还是那么菜)
有两种方法(一种比较直观,一种比较玄学)。
直观的:
考虑对于每个坐标,我们飞到 (x,y) ( x , y ) 所点击的次数实际上是固定的( (x+y)/2 ( x + y ) / 2 ),而且我们也只能飞到横纵坐标奇偶性一样的位置。而且这个小鸟它可以打洞!(飞到纵坐标为负的位置),所以只要飞过最后一个障碍就无所谓了。
我们先把每个障碍的坐标范围更新一下(横纵坐标奇偶性不一样的,如果是上端点就减一下,下端点就加一下)。显然,对于每个障碍,穿过这个障碍可以到达的坐标范围是一个逆时针旋转了九十度的等腰梯形。我们不断传递下去就好了。
代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int n,X,x[N],l[N],r[N],tp,L,R;

inline int rd()
{
    char ch=getchar();int x=0,f=1;
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*f;
}

int main(){
    n=rd();rd();
    for(int i=1;i<=n;++i){
       x[i]=rd();l[i]=rd();r[i]=rd();
       l[i]++;r[i]--;
       if((l[i]&1)^(x[i]&1)) l[i]++;
       if((r[i]&1)^(x[i]&1)) r[i]--;
    }
    for(int i=1;i<=n;++i){
        R+=x[i]-x[i-1];
        L-=x[i]-x[i-1];
        if((R&1)^(x[i]&1))R--;
        if((L&1)^(x[i]&1))L++;
        R= R>r[i]? r[i]:R;
        L= L<l[i]? l[i]:L;
        if(L>R){printf("NIE\n");return 0;}
    }
    printf("%d\n",(x[n]+L)>>1);
}

另一种玄学做法(来自PoPoQQQ):

贪心
预处理f[i]表示第 i...n i . . . n 个柱子中 a[i]x[i] a [ i ] − x [ i ] 的最大值,显然如果我在穿过第 i1 i − 1 个柱子后的某一时刻 yx<=f[i] y − x <= f [ i ] ,那么我就GG了
所以我先下降到这条线上方,然后再一直点就好了。
时间复杂度 O(n) O ( n )
感性理解

//here is another one
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int n,X,x[N],l[N],r[N],lim[N],tp,L,R,ans;

inline int rd()
{
    char ch=getchar();int x=0,f=1;
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*f;
}

int main(){
    n=rd();rd();
    for(int i=1;i<=n;++i){
       x[i]=rd();l[i]=rd();r[i]=rd();
       l[i]++;r[i]--;
       lim[i]=l[i]-x[i];if(lim[i]&1) lim[i]++;
    }
    for(int i=n-1;i>=1;i--) lim[i]=max(lim[i],lim[i+1]);
    for(int i=1;i<=n;++i){
        tp=(R-L)-lim[i]>>1;
        if(tp<0) tp=0;
        tp=x[i]-L-tp;
        if(tp<0) tp=0;
        R+=tp;R-=x[i]-L-tp;
        L=x[i];
        if(R>r[i] || R<l[i]){printf("NIE\n");return 0;}
        ans+=tp;
    }
    printf("%d\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值