我们把这两只青蛙分别叫做青蛙A和青蛙B,并且规定纬度线上东经0度处为原点,由东往西为正方向,单位长度1米,这样我们就得到了一条首尾相接的数轴。设青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。纬度线总长L米。现在要你求出它们跳了几次以后才会碰面。
1 2 3 4 5Sample Output
4
扩展欧几里德算法是用来求解ax+by=gcd(a,b)的解。
--------------------------------------------------------------------------------------------------------------------
首先欧几里德算法(辗转相除法)是求a和b的最大公因数,gcd(a,b) = gcd(b,a % b),直至a % b == 0,则b就是其最大公因数
可以通过递归实现:
int gcd(int a,int b) {
if(b == 0)return a;
return gcd(b,a % b);
}
--------------------------------------------------------------------------------------------------------------------
而扩展算法为:对于不完全为0的非负整数a,b,gcd(a,b)表示a,b的最大公约数,必然存在整数对x,y,使得gcd(a,b) = ax + by。
理解:
ax + by = gcd(a,b) = gcd(b,a%b) = bx' + (a % b)y' = bx' + (a - (a / b) * b)y' = ay' + b(x' - (a / b)y')
即:ax + by = ay' + b(x' - (a / b)y')
则:x = y',y = x' - (a / b)y'
设a > b,当b == 0时,gcd(a,b) = a,所以此时x = 1,y = 0;
以此可以通过递归过程实现:
int extgcd(int a,int b,int *x,int *y) {
if(b == 0) {
*x = 1;*y = 0;
return a;
}
int r = extgcd(b,a % b,y,x);
*y -= (a / b) * (*x);
return r;
}
上面是求ax+by=gcd(a,b)的解的过程
--------------------------------------------------------------------------------------------------------------------
那么如何利用扩展算法求解方程a * x + b * y = n的整数解呢。
1、先计算gcd(a,b),若n不能被gcd(a,b)整除,则方程无整数解;
否则,在方程两边同时除以gcd(a,b),两边约分后得到新的不定方程a' * x + b' * y = n',
此时gcd(a',b') = 1(因为已经除去了最大公约数);
2、利用扩展算法求出方程a' * x + b' * y = 1的一组整数解x0,y0,
则n' * x0,n' * y0是方程a' * x + b' * y = n'的一组整数解;
3、根据数论中的相关定理,可得方程a' * x + b' * y = n'的所有整数解为:
x = n' * x0 + b' * t
y = n' * y0 - a' * t (t为任意整数)
上面的解也就是a * x + b * y = n 的全部整数解
--------------------------------------------------------------------------------------------------------------------
本题:
x + m * t - (y + n * t) = k * l
即(n - m) * t + k * l = x - y
先求r = gcd(n - m,l),如果x - y能被其整除,说明有解,否则没有解
同时求(n - m) * t + k * l = r的解,即求(n - m) / r * t + l / r * k = 1的解t0和k0,
再乘(x - y) / r,得到原方程的解,
我们需要的是[0,l - 1]内的解。
根据定理:若gcd(a, b) = 1,则方程ax ≡ c (mod b)在[0, b-1]上有唯一解。
设rr = l / r,最后的解为 (t0 * (x - y) / r) % rr
c++代码:
#include <iostream> #include <cstdio> #include <cstdlib> using namespace std; long long exgcd(long long a,long long b,long long &x,long long &y) { if(b == 0) { x = 1; y = 0; return a; } long long r = exgcd(b,a % b,x,y); long long t = x - a / b * y; x = y; y = t; return r; } int main() { long long x,y,m,n,l,a,b; cin>>x>>y>>m>>n>>l; long long r = exgcd(n - m,l,a,b); long long rr = l / r; if((x - y) % r) { cout<<"Impossible"; } else { cout<<((x - y) / r * a % rr + rr) % rr;///a 只是 (n - m) * t + k * l = gcd(n - m,l) 的t对应解,需要乘(x - y) / gcd(n - m,l) 才是要求的方程的解 } }
c代码:
#include <stdlib.h> #include <stdio.h> #define inf 0x3f3f3f3f #define MAX 10001 long long extgcd(long long a,long long b,long long *x,long long *y) { if(b == 0) { *x = 1; *y = 0; return a; } long long r = extgcd(b,a % b,x,y); long long t = *x - (a / b) * (*y); *x = *y; *y = t; return r; } int main() { long long x,y,m,n,l,a,b; scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&l); long long r = extgcd(n - m,l,&a,&b); long long rr = l / r; if((x - y) % r)printf("Impossible"); else { printf("%lld",((x - y) / r * a % rr + rr) % rr); } }