大圣在佛祖的手掌中。
我们假设佛祖的手掌是一个圆圈,圆圈的长为 n,逆时针记为:0,1,2,…,n−1,而大圣每次飞的距离为 d。
现在大圣所在的位置记为 x,而大圣想去的地方在 y。
要你告诉大圣至少要飞多少次才能到达目的地。
注意:孙悟空的筋斗云只沿着逆时针方向翻。
输入格式
有多组测试数据。
第一行是一个正整数 T,表示测试数据的组数;
每组测试数据包括一行,四个非负整数,分别为如来手掌圆圈的长度 n,筋斗所能飞的距离 d,大圣的初始位置 x 和大圣想去的地方 y。
输出格式
对于每组测试数据,输出一行,给出大圣最少要翻多少个筋斗云才能到达目的地。
如果无论翻多少个筋斗云也不能到达,输出 Impossible。
数据范围
2<n<10^9,
0<d<n,
0≤x,y<n
输入样例:
2
3 2 0 2
3 2 0 1
输出样例:
1
2
题解
上面证明 转载于 https://zhuanlan.zhihu.com/p/100567253 Pecco
——————————————————————————分割线—————————————————————
好了开始分析题意:
题目给出圆圈长为n,大圣飞的距离是d,从x到y
因此可得等式
x + bd = y (mod n)
=> x + bd = y + an (a、b为未知数)
=> -an + bd = y - x
这个式子中,n、d、y、x都是常数
设 gcd (n,d) 意思是n和d的最大公约数
-an + bd = gcd(n,d) 这个式子符合线性同余方程,使用拓展欧几里得算法可以求知一组解,然后我们判断 gcd(n,d) 是否可以整除 y-x ,可以整除左右两边就乘以 y − x g c d ( n , d ) \frac{y-x}{gcd(n,d)} gcd(n,d)y−x 得出a、b有解时的系数,b的含义为翻筋斗云的次数,要计算 b 的最小值,因为等式
ax+by=d的通解为
{ x k = x + k ∗ b g c d ( a , b ) y k = y − k ∗ a g c d ( a , b ) \begin{cases}x_k=x+k*\frac {b} {gcd(a,b)}\\y_k=y-k*\frac {a} {gcd(a,b)}\end{cases} {xk=x+k∗gcd(a,b)byk=y−k∗gcd(a,b)a ,所以 -an+bd = y-x 等式b的通解为
b k = b − k ∗ n g c d ( n , d ) b_k=b-k*\frac {n} {gcd(n,d)} bk=b−k∗gcd(n,d)n ,因此求最小值, bmin = b mod n g c d ( n , d ) \frac {n} {gcd(n,d)} gcd(n,d)n
#include <iostream>
#include <cstring>
#include <algorithm>
typedef long long LL;
using namespace std;
int exgcd(LL a,LL b,LL &x,LL &y)
{
if(b==0){
x = 1, y = 0;
return a;
}
int d = exgcd(b,a%b,y,x);
y -= a/b*x;
return d;
}
int main()
{
int t;
cin>>t;
while(t--){
LL n,d,x,y;
cin>>n>>d>>x>>y;
LL a,b;
int gcd = exgcd(n,d,a,b);
if((y-x)%gcd==0){
b *= (y-x)/gcd;
n /= gcd;
cout <<( b % n + n ) % n <<endl;
}
else puts("Impossible");
}
return 0;
}