扩展欧几里得___追风少年的坐骑(2016swust信息院赛)


    追风的少年基XX为了赶上风速,他亲自打造了一个坐骑,他的坐骑拥有土豪级别的两个键帽,分别为加速按钮和减速按钮。那么问题来了,他每按一次加速按钮,可以给他的坐骑增加a的速度,每按一次减速按钮,他的坐骑速度会减少b,当速度减少到0的时候,不再减速,但依然可以继续按减速按钮。他坐骑现在的速度为s,但必须达到速度t(必须等于),才能赶上风的速度。还有个更严重的问题,他必须按n次按钮,不然他坐骑上的GTX1080战术核显卡是会BOOM的……基XX想知道,在不引爆显卡的情况下,能不能赶上风的速度。

    输入一排,分别为描述中所叙述的n,s,t,a,b。其中1≤n≤109 0≤s,t≤109 1≤a,b≤109 
    输出一行,如果基XX能赶上风的速度,输出“YES”,否则输出“BOOM”.
4 2 3 3 3
2 1 100 2 2
YES
BOOM


分析:

这个题目可以分为两种情况,

第一种就是在追逐过程中不会降到0,换句话意思就是说存在两个正整数x,y使得 ax+by= t-s 成立并且有 x + y = n,这样两个二元一次方程可以解出x,y如果有整数解,那么说明YES,否则判断第二种情况。

第二种就是在追逐过程中会先降到0,然后再0的时候继续反复减速(也可以不继续减速)然后再加速到 t,这样的情况我们就分为前后两段,第一段是减速到0,很显然这一个过程至少需要 sub(s/b) 次。sub(a)表示对a向上取整。因为速度减为0之后我们可以反复0处通过减速来浪费次数,所以我们要在n - sub(s/b) 次数内 从0上升到t.这样题目就转化为为.

ax+by = t, 并且 x>=0 && y>=0 求x+y的最小值,如果x+y的最小值 小于 n - sub(s/b) 就说明YES,否则就NO. 这里因为 t 的范围很大所以要使用拓展欧几里得来求解。循环判断要超时。

ax+by = t 显然 t % gcd(a,b) == 0 才有解。令 t / gcd = c . 那么 求得一组特殊解 x0a + y0b = gcd .那么 cx0 ,cy0 就是 ax+by = t 的一组特解。那么通解是什么呢?

x = cx0 + b/gcd * m

y = cy0 - a/gcd * m 


然后就可以用这两个式子来求得x,y。


代码:

#include <stdio.h>
#include <string.h>
 
long long MAX(long long a,long long b)
{
    return a>b?a:b;
}
long long MIN(long long a,long long b)
{
    return a<b?a:b;
}
 
long long e_gcd(long long a,long long b,long long &x,long long &y)
{
    if(b == 0){
        x = 1;
        y = 0;
        return a;
    }
    long long ans = e_gcd(b,a%b,y,x);
    y = y - a/b*x;
    return ans;
}
bool tz_gcd(long long a,long long b,long long c,long long& x,long long& y)
{
    long long gcd;
    gcd = e_gcd(a,b,x,y);
    if(c % gcd != 0)
    {
        return false;
    }
    else
    {
        x = c / gcd * x;
        y = c / gcd * y;
        if( x > 0 && y < 0 )
        {
              long long t = 0;
              t = x / (b/gcd);
              t = MIN(t,-y/(a/gcd));
              x = x - b/gcd * t;
              y = y + a/gcd * t;
        }
        else
        {
            long long t = 0;
            if( x < 0)
            {
                if( (-x * gcd) % b == 0) t = (-x*gcd)/b;
                else t = (-x * gcd)/b + 1;
            }
            if( y > 0)
            {
                if( (y * gcd) % a == 0 ) t = MAX(t,(y*gcd)/a);
                else t = MAX(t,(y*gcd)/a+1);
            }
            x = x + b/gcd * t;
            y = y - a/gcd * t;
 
        }
    }
    return true;
}
 
bool Jianjie(long long n,long long s,long long t,long long a,long long b)
{
    long long c;
    if( s % b == 0) c = s / b;
    else c = s / b + 1;
 
    long long x,y;
    if(!tz_gcd(a,b,t,x,y)) return false;
    y = -y;
    if( c + x + y <= n) return true;
    return false;
}
 
int main()
{
    long long n,s,t,a,b;
    while(scanf("%lld%lld%lld%lld%lld",&n,&s,&t,&a,&b)!=EOF)
    {
        if((t + n * b - s) % (a+b) == 0)
        {
            printf("YES\n");
            continue;
        }
        if(Jianjie(n,s,t,a,b))
        {
            printf("YES\n");
            continue;
        }
        printf("BOOM\n");
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值