/**
题目:青蛙的约会
链接:https://vjudge.net/contest/154246#problem/R
题意:一个跑道长为周长为L米,两只青蛙初始位置为x,y;(x!=y,同时逆时针运动,每一次运动分别为m,n米;问第几次运动后相遇,即在同一位置。
如果永远无法相遇输出Impossible。
思路:
设:次数为t;
圈总长为: L
A位置:(x+m*t)%L;
B位置: (y+n*t)%L;
如果: (x+m*t)%L = (y+n*t)%L 存在碰面; 暴力枚举t。太大了;
保证m,n<L; m%=L; n%=L; 又x!=y;
=> (x+m*t - (y+n*t)) %L = 0;
设:x+m*t-y-n*t = L*k; (k为整数);
=>(x-y)+(m-n)*t = L*k;
L*k-(m-n)*t = (x-y); 未知数(k, t);
换位置:(m-n)*t - L*k = (y-x)
令:ax+by = c;
a = m-n;
b = -L;
c = y-x;
然后根据:
方程ax+by=c的整数解(a,b,c为整数)
令g=gcd(a,b), 很明显,c不是g的倍数时方程无解。如果c等于g,用扩展欧几里德算法求得一组解(x0,y0). 如果c是g的倍数,则相应的一组解(x0*c/g,y0*c/g).
若方程存在解(x1,y1),则通解形式为(x1+k*b/g, y1-k*a/g), k为任意整数
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf = 0x3f3f3f3f;
const int maxn = 1e5+10;
const double eps = 1e-6;
ll gcd(ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
ll ext_gcd(ll a,ll b,ll &x,ll &y)
{
ll ret, tmp;
if(!b){
x = 1, y = 0; return a;
}
ret = ext_gcd(b,a%b,x,y);
tmp = x;
x = y;
y = tmp-a/b*y;
return ret;
}
int main()
{
ll x, y, m, n, L;
while(scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&L)!=EOF)
{
ll a, b, c;
a = m-n;
b = -L;
c = y-x;
if(c%gcd(a,b)!=0){
printf("Impossible
"); continue;
}
ll xx, yy;
ll d = ext_gcd(a,b,xx,yy);
ll add = b/d;
ll t = xx*c/d;
if(add<0) add = -add;
t %= add;
if(t<=0) t+=add;
printf("%lld
",t);
}
return 0;
}
下面这一份是自己最开始写的方法。很繁琐。
/**
题目:青蛙的约会
链接:https://vjudge.net/contest/154246#problem/R
题意:一个跑道长为周长为L米,两只青蛙初始位置为x,y;(x!=y,同时逆时针运动,每一次运动分别为m,n米;问第几次运动后相遇,即在同一位置。
如果永远无法相遇输出Impossible。
思路:
设:次数为t;
圈总长为: L
A位置:(x+m*t)%L;
B位置: (y+n*t)%L;
如果: (x+m*t)%L = (y+n*t)%L 存在碰面; 暴力枚举t。太大了;
保证m,n<L; m%=L; n%=L; 又x!=y;
=> (x+m*t - (y+n*t)) %L = 0;
设:x+m*t-y-n*t = L*k; (k为整数);
=>(x-y)+(m-n)*t = L*k;
L*k-(m-n)*t = (x-y); 未知数(k, t);
令:ax+by = c;
a = L;
b = -(m-n);
c = (x-y);
为了保证c为正数,所以要处理一下符号关系。暂且当做已经处理过。
把负号都放入未知数中。那么要判断是否这样处理过,如果处理过,那么得出来的K,t要取反。
题目应该是求最小的满足的解t>=1;
然后根据:
方程ax+by=c的整数解(a,b,c为整数)
令g=gcd(a,b), 很明显,c不是g的倍数时方程无解。如果c等于g,用扩展欧几里德算法求得一组解(x0,y0). 如果c是g的倍数,则相应的一组解(x0*c/g,y0*c/g).
若方程存在解(x1,y1),则通解形式为(x1+k*b/g, y1-k*a/g), k为任意整数
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf = 0x3f3f3f3f;
const int maxn = 1e5+10;
const double eps = 1e-6;
ll gcd(ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
ll ext_gcd(ll a,ll b,ll &x,ll &y)
{
ll ret, tmp;
if(!b){
x = 1, y = 0; return a;
}
ret = ext_gcd(b,a%b,x,y);
tmp = x;
x = y;
y = tmp-a/b*y;
return ret;
}
int main()
{
ll x, y, m, n, L;
while(scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&L)!=EOF)
{
int flag = 0;///flag==0表示正数,否则表示负数;
ll a, b, c;
a = L;
b = m>n?(m-n):(n-m);
c = x>y?(x-y):(y-x);
if(m-n==0){
printf("Impossible
"); continue;
}
if(x>y){
if(m>n) flag = 1;
}else
{
if(m<n) flag = 1;
}
if(c%gcd(a,b)!=0){
printf("Impossible
"); continue;
}
ll xx, yy;
ll d = ext_gcd(a,b,xx,yy);
ll ans = inf;
ll add = -a/d;//<0
ll t = yy*c/d;
if(flag){///t应该为负数,取反才为正数。
if(t>=0){
t %= (-add);
while(t>=0){
t += add;
}
ans = -t;
}else
{
t = (-t)%(-add);
t = -t;
if(t==0){
ans = -add;
}
while(t<0){
ans = -t;
t -= add;
}
}
}else
{///t应该为正数。
if(t>0){
t %= (-add);
while(t>0){
ans = t;
t += add;
}
}else
{
t = (-t)%(-add);
t = -t;
while(t<=0){
t -= add;
}
ans = t;
}
}
if(ans==inf){
printf("Impossible
"); continue;
}else
printf("%lld
",ans);
}
return 0;
}