牛客练习赛111
D 青蛙兔子的约会
题目大意就是兔子和青蛙在同一条坐标轴上,青蛙可以朝着兔子的方向跳[l,r]步,每步跳a距离,兔子可以朝任意方向跳无限步,每步距离为b,询问他俩会不会在同一坐标
算法: 思维 gcd exgcd
我们发现,这道题的求解就是在解一个二元一次方程
a*x + by = n 看在[l,r]中是否x有解
这时候 扩展欧几里得算法求解二元一次方程组就出来了
这样我们可以求出来一组特解x0, y0
光有特解还是不够的,我们通过gcd就可以求出来通解了
x = x0 + b/gcd(a,b) 范围是实数域
这时候我们就把x0 往[l,r]中去靠,如果可以靠近去,那么就YES否者就是NO
算法的具体实现推导都在代码里了
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
ll a, b, l, r, n;
int t;
ll exgcd(ll a, ll b, ll &x, ll &y)
{
if(b == 0)
{
x = 1; // ax + by = gcd(a, b) => a + 0 = gcd(a, 0);
y = 0;
return a;
}
ll gcd = exgcd(b, a % b, x, y);
//推导过程
// a, b ax + by = gcd(a, b)
// b a%b bx1 + (a-a/b*b)y1 = gcd(a, b)
// => ay1 + b(x1-a/b*y1) = gcd(a, b)
// x = y1, y = (x1 - a/b*y1)
ll tem = y;
y = (x - a/b * y);
x = tem;
return gcd;
}
int main()
{
cin >> t;
while(t --)
{
ll x, y;
cin >> a >> b >> n >> l >> r;
ll gcd = exgcd(a, b, x, y);
if(n % gcd)
{
puts("NO");
}
else
{
x *= n / gcd;
y *= n / gcd;
//通解 x = x0 + k * b/gcd 范围是全体实数
// y = y0 - k * a/gcd 范围是全体实数
// 最小正整数 x = (x0 + b/gcd) % (b/gcd);
//把x靠到l-r里面去
ll d = b / gcd;
if(x < l)
{
//上取整
x += ((l - x + d - 1)/d * d);
}
else if(x > r)
{
x -= ((x - r + d - 1)/d * d);
}
if(x >= l && x <= r)
{
puts("YES");
}
else
{
puts("NO");
}
}
}
return 0;
}