Date:2022.03.31
题意描述:
大圣在佛祖的手掌中。
我们假设佛祖的手掌是一个圆圈,圆圈的长为 n,逆时针记为:0,1,2,…,n−1,而大圣每次飞的距离为 d。
现在大圣所在的位置记为 x,而大圣想去的地方在 y。
要你告诉大圣至少要飞多少次才能到达目的地。
注意:孙悟空的筋斗云只沿着逆时针方向翻。
输入格式
有多组测试数据。
第一行是一个正整数 T,表示测试数据的组数;
每组测试数据包括一行,四个非负整数,分别为如来手掌圆圈的长度 n,筋斗所能飞的距离 d,大圣的初始位置 x 和大圣想去的地方 y。
输出格式
对于每组测试数据,输出一行,给出大圣最少要翻多少个筋斗云才能到达目的地。
如果无论翻多少个筋斗云也不能到达,输出 Impossible。
数据范围
2<n<109,
0<d<n,
0≤x,y<n
输入样例:
2
3 2 0 2
3 2 0 1
输出样例:
1
2
思路:由题可得
(
x
+
k
1
∗
d
)
%
n
=
=
y
(x+k1*d)\%n==y
(x+k1∗d)%n==y,即
d
∗
k
1
+
n
∗
k
2
=
=
y
−
x
d*k1+n*k2==y-x
d∗k1+n∗k2==y−x,因此
g
c
d
(
d
,
n
)
∤
(
y
−
x
)
gcd(d,n) \nmid (y-x)
gcd(d,n)∤(y−x)则无解,否则解为
d
∗
k
1
′
+
n
∗
k
2
′
=
=
g
c
d
(
d
,
n
)
d*k1'+n*k2'==gcd(d,n)
d∗k1′+n∗k2′==gcd(d,n)时的一组
(
k
1
′
,
k
2
′
)
(k1',k2')
(k1′,k2′),而
(
k
1
,
k
2
)
=
=
(
y
−
x
)
/
g
c
d
(
d
,
n
)
∗
(
k
1
′
,
k
2
′
)
(k1,k2)==(y-x)/gcd(d,n)*(k1',k2')
(k1,k2)==(y−x)/gcd(d,n)∗(k1′,k2′)为
d
∗
k
1
+
n
∗
k
2
=
=
y
−
x
d*k1+n*k2==y-x
d∗k1+n∗k2==y−x的一组解。但由于要使得翻跟头数最小,即
k
1
k1
k1最小为
m
i
n
k
1
mink1
mink1,我们还需操作。由方程的解特性可得:
{
k
k
1
=
k
1
+
t
∗
n
g
c
d
(
n
,
d
)
k
k
2
=
k
2
−
t
∗
d
g
c
d
(
n
,
d
)
\left\{ \begin{array}{lr} kk1=k1+t*\frac{n}{gcd(n,d)} \\ kk2=k2-t*\frac{d}{gcd(n,d)} \\ \end{array} \right.
{kk1=k1+t∗gcd(n,d)nkk2=k2−t∗gcd(n,d)d
由此,为使得
k
k
1
kk1
kk1最小为
m
i
n
k
1
mink1
mink1,
k
k
1
kk1
kk1需要是最小正数,也就是不能再被
n
g
c
d
(
n
,
d
)
\frac{n}{gcd(n,d)}
gcd(n,d)n除,也就相当于在保证为正数的前提下
%
n
g
c
d
(
n
,
d
)
\%\frac{n}{gcd(n,d)}
%gcd(n,d)n。
代码如下:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(!b) {x=1,y=0;return a;}
LL d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main()
{
LL t,n,d,x,y;
cin>>t;
while(t--)
{
cin>>n>>d>>x>>y;
LL x0,y0;
LL dd=exgcd(d,n,x0,y0);
if((y-x)%dd) cout<<"Impossible\n";
else
{
LL k=(y-x)/dd;
x0*=k;y0*=k;
cout<<(x0%(n/dd)+(n/dd))%(n/dd)<<'\n';
}
}
return 0;
}