这辈子就指着AC题目活了。
题意:
一根长为l的环形数轴上有两只青蛙,他们的初始位置坐标分别为x和y,他们同时开始向一个方向跳,A青蛙一次跳m米,B青蛙一次跳n米,每次跳的时间相等,如果某一时刻他们处于同一个坐标,则相遇,问他们能否相遇?若能最少要跳多少次。
Input
输入只包括一行5个整数x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。
Output
输出碰面所需要的跳跃次数,如果永远不可能碰面则输出一行"Impossible"
数据范围很大,第一次做这个题的时候试图跑循环,结果TLE到死,方程很好列不再写,用扩展欧几里的算法,下面详写一下欧几里的算法。
一. 欧几里的算法,辗转相除法。
用来求两个整数最大公因数的算法,是其扩展算法的基础。
设gcd(x,y)=a,x=m*a, y=n*a
可证(x%y)|a: x%y=x-x/y*y, x|a, y|a, 因此(x%y)|a。
因此,a是y和x%y的公因数。
假设存在b!=a,为y和x%y的最大公因数
因为b是y的因数,且已证a是y和x%y的公因数,
不妨设b=k*a (k>1)。
则 y / b = y / ( k * a ) = n / k为整数
( x % y ) / b = ( x - x / y * y ) / b = x / b - ( x / y ) * y / b = m / k - ( x / y ) * n / k, 已证n / k为整数,所以 m|k,与m,n互质矛盾,所以a就是y和x%y的最大公因数
二. 扩展欧几里的
对于不全为0的整数对a, b,必存在整数x, y,使得gcd( a, b) = a * x+b * y。
直观地来说就是可以用这个算法求二元一次方程的一个特解,并得到通解。
算法等价于
a*x1+b*y1=gcd(a,b)
b*x2+(a%b)*y2=gcd(b,a%b)
这两个等式。
证明:
由欧几里的算法可知,gcd(a,b)=gcd(b,a%b),因此a*x1+b*y1=b*x2+(a%b)*y2
右边=b*x2+( a - a / b * b )*y2=a * y2 + b * ( x2 - a / b * y2).
由于等式恒等,所以x1=y2, y1=x2-a/b*y2
得到特解x0, y0后,x0加减b/gcd(a,b) , y0加减a/gcd(a,b)得到其他解,
a*x+b*y=z (z为常数) 等价于 a/gcd(a,b)*x + b/gcd(a,b) *y =z*gcd(a,b),
此时x, y前面的系数互质,而x,y为整数。
题目代码如下:
数据范围很大,第一次做这个题的时候试图跑循环,结果TLE到死,方程很好列不再写,用扩展欧几里的算法,下面详写一下欧几里的算法。
一. 欧几里的算法,辗转相除法。
用来求两个整数最大公因数的算法,是其扩展算法的基础。
int gcd(int x,int y){
return y==0?x:gcd(y,x%y);
}
要证明辗转相除法的正确性,就要证明gcd(x,y)==gcd(y,x%y)。设gcd(x,y)=a,x=m*a, y=n*a
可证(x%y)|a: x%y=x-x/y*y, x|a, y|a, 因此(x%y)|a。
因此,a是y和x%y的公因数。
假设存在b!=a,为y和x%y的最大公因数
因为b是y的因数,且已证a是y和x%y的公因数,
不妨设b=k*a (k>1)。
则 y / b = y / ( k * a ) = n / k为整数
( x % y ) / b = ( x - x / y * y ) / b = x / b - ( x / y ) * y / b = m / k - ( x / y ) * n / k, 已证n / k为整数,所以 m|k,与m,n互质矛盾,所以a就是y和x%y的最大公因数
二. 扩展欧几里的
对于不全为0的整数对a, b,必存在整数x, y,使得gcd( a, b) = a * x+b * y。
直观地来说就是可以用这个算法求二元一次方程的一个特解,并得到通解。
int ex_gcd(int a,int b,int& x,int& y){
if(!b){
x=1;y=0;
return a;
}
int ret=ex_gcd(b,a%b,x,y);
int tem=x;
x=y;
y=tem-a/b*y;
return ret;
}
这份代码就是求a*x+b*y=gcd(a,b)的解x, y,返回a和b的最大公因数。算法等价于
a*x1+b*y1=gcd(a,b)
b*x2+(a%b)*y2=gcd(b,a%b)
这两个等式。
证明:
由欧几里的算法可知,gcd(a,b)=gcd(b,a%b),因此a*x1+b*y1=b*x2+(a%b)*y2
右边=b*x2+( a - a / b * b )*y2=a * y2 + b * ( x2 - a / b * y2).
由于等式恒等,所以x1=y2, y1=x2-a/b*y2
得到特解x0, y0后,x0加减b/gcd(a,b) , y0加减a/gcd(a,b)得到其他解,
a*x+b*y=z (z为常数) 等价于 a/gcd(a,b)*x + b/gcd(a,b) *y =z*gcd(a,b),
此时x, y前面的系数互质,而x,y为整数。
题目代码如下:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
long long x,y,m,n,l;
long long ex_gcd(long long a,long long b,long long& x,long long& y){
if(!b){
x=1,y=0;
return a;
}
int ret=ex_gcd(b,a%b,x,y);
int tem=x;
x=y;
y=tem-a/b*y;
return ret;
}
int main(){
while(scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&l)!=EOF){
long long t,k;
long long r=ex_gcd(n-m,l,t,k);
if((x-y)%r) puts("Impossible");
else{
long long ans=t*(x-y)/r;
long long tem=l/r;
ans=(ans%tem+tem)%tem;
printf("%lld\n",ans);
}
}
return 0;
}