【POJ1061】【洛谷P1516】青蛙的约会

问题描述

【POJ1061】【洛谷P1516】青蛙的约会

输入格式

【POJ1061】【洛谷P1516】青蛙的约会

输出格式

【POJ1061】【洛谷P1516】青蛙的约会

样例输入

1 2 3 4 5

样例输出

4

题解

已知两只青蛙的初始位置和每一步跳的距离,求两只青蛙跳到同一点的最短时间,设最小时间为t,可得:

(x+m*t)-(y+n*t)=p*L

这个式子是个二元一次方程,而我们学过用扩展欧几里德求二元一次方程的解,其中二元一次方程的形式为

a*x+b*y=c

把上面的式子转化成相似形式可得

(n-m)*t+L*p=x-y  (*)

令:a=n-m, b=L, c=gcd(a,b), d=x-y

得:a*t+b*p=d  (1)

那么我们可以用扩展欧几里德求出一组t0,p0,使得

a*t0+b*p0=c  (2)

(1)式两边同除c得:a*t/c+b*p/c=d/c

易知a*t/c和b*p/c是整数,所以d/c也是整数,否则无解。

(2)式两边同乘(d/c)得:a*t0*(d/c)+b*p0*(d/c)=d

所以t0*(d/c)为最小的解,但有可能为负数,为使最终答案为正,解为

(t0*(d/c)%(b/c)+(b/c))%(b/c)

本题有个陷阱,两只青蛙谁在前谁在后是不确定的,但我们可以通过调整使第一只青蛙在前。

 1 #include <cstdio>
 2 #define ll long long
 3 ll exgcd(ll a,ll b,ll &x,ll &y)
 4 {
 5     if (!b)
 6     {
 7         x=1,y=0;
 8         return a;
 9     }
10     ll ans=exgcd(b,a%b,x,y),t;
11     t=x,x=y,y=t-a/b*y;
12     return ans;
13 }
14 int main()
15 {
16     ll gcd,X,Y,x,y,m,n,l,a,b,c,t;
17     scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&l);
18     a=n-m,c=x-y;
19     if (a<0) a=-a,c=-c;
20     gcd=exgcd(a,l,X,Y);  b=l/gcd;
21     if (c%gcd) printf("Impossible");
22     else printf("%lld",(c/gcd*X%b+b)%b);
23     return 0;
24 }