问题描述
原题来自:NEFU 84
大圣在佛祖的手掌中。
我们假设佛祖的手掌是一个圆圈,圆圈的长为 n,逆时针记为:0,1,2,⋯,n−1,而大圣每次飞的距离为 d。现在大圣所在的位置记为 x,而大圣想去的地方在 y。要你告诉大圣至少要飞多少次才能到达目的地。
输入
有多组测试数据。
第一行是一个正整数 T,表示测试数据的组数;
每组测试数据包括一行,四个非负整数,分别为如来手掌圆圈的长度 n,筋斗所能飞的距离 d,大圣的初始位置 x 和大圣想去的地方 y。
注意孙悟空的筋斗云只沿着逆时针方向翻。
输出
对于每组测试数据,输出一行,给出大圣最少要翻多少个筋斗云才能到达目的地。如果无论翻多少个筋斗云也不能到达,输出 Impossible。
样例输入
2
3 2 0 2
3 2 0 1
样例输出
1
2
提示
数据范围与提示:
对于全部数据,2<n<109,0<d<n,0≤x,y<n。
问题分析
拓展欧几里得算法,实际上又是求ax+by=c这个式子中的x;本题的式子其实就是x+ad=y+bn——(a代表翻了几次跟斗,b代表着绕了多少圈)转换一下就是求ad-bn=y-x中a的解。
算法设计
利用扩展欧几里得算法,只需要套用Exgcd模板,求出最小正整数解就是了。
代码
#include<iostream>
using namespace std;
#define ll long long
ll ex_gcd(ll a,ll b,ll &x,ll &y) //扩展欧几里得算法代码模板,可求逆元,也可以求最大公约数。
{
if(b==0)
{
x=1;y=0;
return a;
}
ll r=ex_gcd(b,a%b,x,y);
ll temp=x;
x=y;
y=temp-(a/b)*y;
return r;
}
int main()
{
ll t;
cin>>t;
ll n,d,x,y,X,Y;
while(t--)
{
cin>>n>>d>>x>>y;
ll k=ex_gcd(d,n,X,Y);
n=n/k;
if((y-x)%k!=0) //其实就是ax+by=c中c%gcd(a,b)==0才有整数解!此处c=y-x;
cout<<"Impossible"<<endl;
else
{
cout<<((X*(y-x)/k)%n+n)%n<<endl;
} //实际上就是X*c/gcd(a,b),出现负数的情况需要加n再模n。
}
return 0;
}
算法复杂度分析
扩展欧几里得算法是递归算法,该算法的时间复杂度为O(nlogn)。