首先要知道扩展欧几里得,说白了就是解二元一次方乘,二元一次的话肯定有多解,看题目要求求出最优解。
设一共跳了t次
(x + m*t) % l = (y + n*t)
可以化简为:
(m - n)*t % l = y - x
设取余的时候去掉了k个l,那么可以化简为:
(m - n)*t + l*k = y - x
显然这是一个方乘
然后套用扩展欧几里得
int extgcd(int a, int b, int &x, int &y) {
if(!b) {
x = 1;
y = 0;
return a;
}else {
int r = extgcd(b, a%b, y, x);
y -= x * (a / b);
return r;
}
}
上面的代码并没有用到ax+by=c中的c,因为我们计算出的是与答案的最小公倍数
举一个例子
6x + 15y = 9 return 的值是 3 ,
6*(-2) + 15*1=3,两边同时乘以3,
6*(-6) + 15*3 = 9,x=-6,y=3,就是一组解;
所以我们首先判断return的数字是不是可以被c整除,不能的话就是无解
令gcd = extgcd(a,b,x,y),c=y-x;
t = (t * cgcd ) % lgcd
最后一步的解释
设要解的方程(求x)是:
a x1 + b y1 = c
而我们已经解得
ax + by = gcd(a,b) = d
此时将第二个方程左右同时乘c/d,则可得:
ax∗ cd +by∗ cd =c
所以:
x1 =x ∗ cd
这样并没有完,因为这只是一组解,我们要求最小正整数解。
我们知道:若一组 < x,y > 是ax+by=c的一组解,那么
< x− bd ,y+ ad >
也是原方程的一组解。
这样我们只需要让解得的x不断减b/d,直到再减就为负数时,所得的x就是我们要的解。
#include<iostream>
#define ll long long
using namespace std;
ll extgcd(ll a, ll b, ll &x, ll &y) {
if(!b) {
x = 1;
y = 0;
return a;
}else {
ll r = extgcd(b, a%b, y, x);
y -= x * (a / b);
return r;
}
}
int main() {
ll x, y, m, n, l;
while(cin >> x >> y >> m >> n >> l) {
if(m == n) puts("Impossible");
else {
if(m < n) swap(m, n), swap(x, y);
ll a = m - n;
ll c = y - x;
ll gcd = extgcd(a, l, x, y);
if(c % gcd) {
puts("Impossible");
}else {
printf("%lld\n", ((x*c/gcd)%(l/gcd)+(l/gcd))%(l/gcd));//展开取余,怕超范围
}
}
}
return 0;
}