本文出自:http://blog.csdn.net/svitter
题意:青蛙绕圈跳, 初始位置X,Y,速度M,N,方向相反,L为模。最后能否相遇?相遇时间是什么?
本题目为扩展欧几里德,扩展欧几里德介绍:
关于扩展欧几里德方程
ax + by = c (1)
可以用来求是否有解。即是否存在c满足这个方程。
exgcd(a, b, x, y)是用来求ax + by = gcd(a, b)中x的值和y的值的。如果仅仅只是判断(1)是否有解,直接看gcd(a, b)能否整除c即可。
然后开始分析本题:
设最后在坐标s相遇,A转了b圈,B转了b`圈,花费时间为a,那么可以得到两个方程:
Ma + X = Lb + s; (3)
Na + Y = Lb` + s; (4)
如果s有解,那么方程 (M - N)a+L(b - b`) = Y - X有解。(即(3) - (4))
以此判断impossible的情况;(一开始做的时候没弄懂题意,以为不同方向,shit- -)
解出的a可能不是一个正数,或者比最小数大。
通解为
x1 = x + L / gcd(m-n, L) * t; t为任意整数;
y1 = y - L / gcd(m-n,L) * t;
证明:
已知ax + by = c
ax1 = x * a + lcm(a, b) * t;
by1 = y * b - lcm(a, b)*t;
所以ax1 + by1 = c;
代码如下:
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define lln long long int
lln gcd(lln a, lln b)
{
if(b == 0)
return a;
return gcd(b, a % b);
}
lln exgcd(lln a, lln b, lln &x, lln &y)
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
int d = exgcd(b, a % b, x, y);
int t = x;
x = y;
y = t - (a / b) * y;
return d;
}
void ace()
{
lln X, Y, M, N, L;
lln dis;
lln a, b, x, y, c, gc, d;
while(scanf("%lld %lld %lld %lld %lld", &X, &Y, &M, &N, &L) == 5)
{
a = M - N;
c = exgcd(a, L, x, y);
dis = Y - X;
if(dis % c != 0)
{
printf("Impossible\n");
continue;
}
x = x * (dis / c);
y = y * (dis / c);
gc = L / c;
gc = gc > 0? gc : -gc;
while(x > 0)
{
x -= gc;
}
while(x < 0)
{
x += gc;
}
printf("%lld\n", x);
}
}
int main()
{
ace();
return 0;
}
原文地址:http://blog.csdn.net/svitter/article/details/24632725