题目大意: 给一个长度为 L L L 的圆环,有两只青蛙,给出两者的起点和速度,问何时相遇。
题解
显然是个追击问题,先列出柿子:
x
+
t
n
≡
y
+
t
m
(
m
o
d
L
)
x+tn\equiv y+tm \pmod L
x+tn≡y+tm(modL)
其中 t t t 即为我们要求的答案,其他的变量意义如题所述。
那么我们大力变换:
x
+
t
n
≡
y
+
t
m
(
m
o
d
L
)
x
−
y
+
t
(
n
−
m
)
≡
0
(
m
o
d
L
)
\begin{aligned} x+tn&\equiv y+tm \pmod L\\ x-y+t(n-m)&\equiv 0 \pmod L \end{aligned}
x+tnx−y+t(n−m)≡y+tm(modL)≡0(modL)
不妨设
A
=
x
−
y
,
B
=
m
−
n
A=x-y,B=m-n
A=x−y,B=m−n,那么有:
A
−
t
B
≡
0
(
m
o
d
L
)
A-tB\equiv 0 \pmod L
A−tB≡0(modL)
这个
(
m
o
d
L
)
\pmod L
(modL) 有点棘手,不妨设多一个
k
L
kL
kL 带进去,有
A
−
t
B
=
k
L
k
L
+
t
B
=
A
\begin{aligned} A-tB&= kL\\ kL+tB&=A \end{aligned}
A−tBkL+tB=kL=A
根据裴蜀定理,如果 A A A 不是 ( L , B ) (L,B) (L,B) 的倍数,那么该方程无解,此时输出 ′ ′ I m p o s s i b l e ′ ′ ''Impossible'' ′′Impossible′′。
如果有解,还要注意, B B B 不能是负数,所以如果 B B B 是负数的话就要将 A , B A,B A,B 同时取反,这是不影响答案的。(回到 A − t B ≡ 0 ( m o d L ) A-tB\equiv 0 \pmod L A−tB≡0(modL) 这个柿子就能明白)
那么我们可以用
e
x
g
c
d
exgcd
exgcd 求出下面这个方程的一组合法解:
k
L
+
t
B
=
gcd
(
L
,
B
)
kL+tB=\gcd(L,B)
kL+tB=gcd(L,B)
对于求出来的一组合法的解 k 1 , t 1 k_1,t_1 k1,t1,并不一定是最后的答案,我们要的是最小的 t 1 t_1 t1,所以我们还得搞一搞。
设 g = gcd ( L , B ) g=\gcd(L,B) g=gcd(L,B),我们发现,让 t 1 t_1 t1 加 L g \frac L g gL 再让 k 1 k_1 k1 减 B g \frac B g gB,这样又能得到一组另外的合法的解,那么我们不妨让 t 1 t_1 t1 对 L g \frac L g gL 取模,那么就能得到最小解了。
但是我们求出的是 k L + t B = gcd ( L , B ) kL+tB=\gcd(L,B) kL+tB=gcd(L,B) 这个方程的最小解,要让整个方程乘以 A gcd ( L , B ) \frac A {\gcd(L,B)} gcd(L,B)A,才能得到原方程的最小解。(注意这个解也需要对 L g \frac L g gL 取模)
于是代码如下:
#include <cstdio>
#include <cstring>
#define ll long long
ll x,y,n,m,L;
ll gcd(ll x,ll y){return y==0?x:gcd(y,x%y);}
void exgcd(ll a,ll b,ll &xx,ll &yy)
{
if(b==0){xx=1;yy=0;return;}
exgcd(b,a%b,yy,xx);
yy-=a/b*xx;
}
int main()
{
scanf("%lld %lld %lld %lld %lld",&x,&y,&n,&m,&L);
ll A=x-y,B=m-n,k,t,g;
if(B<0)A=-A,B=-B;
g=gcd(L,B);//注意,要在B判负之后再求gcd
if(A%g!=0)return printf("Impossible"),0;
exgcd(L,B,k,t);
t*=A/g;
t=(t%(L/g)+L/g)%(L/g);//注意负数的情况
printf("%lld",t);
}