POJ

来源:互联网 发布:银行卡四件套淘宝网 编辑:程序博客网 时间:2024/05/17 04:51

首先要知道扩展欧几里得,说白了就是解二元一次方乘,二元一次的话肯定有多解,看题目要求求出最优解。
设一共跳了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)是:

ax1 + by1 = 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 longusing 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;}