ZOJ3593扩展欧几里得之线性方程

来源:互联网 发布:cms下载 编辑:程序博客网 时间:2024/05/17 02:23
//题目连接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4677//题目大意:每次可以向左或者向右走a或者b或者(a+b)步.问在数轴上从A->B最少需要多少次.//解题思路:式子ax+by=c;如果x>0&&y>0 那么ans=max(x,y);if(x<0&&y>0)ans=y-x//         所以就是去求一组解(x,y)使得上面的ans最小..//         在采用EXGCD求得一组解之后(这里注意.这里的解有可能很大.10^14).分别讨论1.x<0&&y>0//         2.x>0&&y>0   3.x>0&&y<0 .. 这三种情况的时候t存在一个范围.//         (因为t范围是由分式得来.所以开始做的时候通过两边同乘来讨论t,后来发现t很大.做乘法会超过LL)//         后来直接用分式去计算t能够所在区间范围..然后在三组优解中找到一个最优解即可.#include<stdio.h>#include<stdlib.h>#include<iostream>#include<math.h>#include<vector>#include<string.h>#include<algorithm>using namespace std;#define LL long longLL GCD(LL a , LL b){    if(a > b)    {        LL c = a;        a = b;        b = c ;    }    while(a)    {        LL m = a;        a = b%a;        b = m;    }    return b;}void exGCD(LL a , LL b , LL& x , LL& y){    if(!b)    {        x = 1;        y = 0;        return ;    }    else exGCD(b,a%b,y,x);    y -= x * (a / b);}LL judge(LL x , LL y){    // printf("%lld  %lld\n",x,y);    if(x >= 0 && y >= 0)    {        if(x > y)return x;        return y;    }    if(x >= 0 && y <= 0)return x - y;    if(x <= 0 && y >= 0)return y - x;    return 0x3f3f3f3f;}LL sum(LL x , LL y ,LL p , LL q , LL t){    x = x + p * t;    y = y - q * t;    return judge(x,y);}bool get(LL x , LL y){    if(x < 0) x = - x;    if(x % y == 0)return 1;    return 0;}LL solve(LL a , LL b , LL c){    LL x , y;    LL ans = 1e18;    LL p = GCD(a,b);    if(c % p != 0)return -1;    exGCD(a,b,x,y);    x *= c / p ;    y *= c / p;    ans = min(ans , judge(x,y));    LL q = a/p;    p = b/p;    LL t ,t1,t2;    if(x >= 0 && y <= 0)    {        if(get(-x , p))t1 = (-x) / p;        else t1 = - (x / p);        if(get(y , q))t2 = y / q;        else t2 = - (-y / q);        t = max(t1,t2);        ans = min(ans , sum(x,y,p,q,t));        if(get(y , q))t2 = y / q;        else t2 = - ((-y) / q + 1);        t = (y-x)/(p+q);        if(t1 <= t2)        {            if(t >= t1 && t <= t2)            {                ans = min(ans , sum(x,y,p,q,t));                ans = min(ans , sum(x,y,p,q,t + 1));                ans = min(ans , sum(x,y,p,q,t - 1));            }            else            {                if(t1 > t)                    ans = min(ans , sum(x,y,p,q,t1));                else ans = min(ans , sum(x,y,p,q,t2));            }        }        if(get(-x , p))t1 = (-x) / p;        else t1 = - (x / p + 1);        t = min(t1,t2);        ans = min(ans , sum(x,y,p,q,t));    }    else    {        if(get(-x,p))t1 = -x / p;        else t1 = (-x) / p;        if(get(y,q))t2 = y / q;        else t2 = y / q;        t = min(t1,t2);        ans = min(ans , sum(x,y,p,q,t));        if(get(-x,p))t1 = -x / p;        else t1 = (-x) / p + 1;        t = (y - x) / (p + q);        if(t1 <= t2)        {            if(t >= t1 && t2 >= t)            {                ans = min(ans , sum(x,y,p,q,t));                ans = min(ans , sum(x,y,p,q,t-1));                ans = min(ans , sum(x,y,p,q,t+1));            }            else            {                if(t < t1)ans = min(ans , sum(x,y,p,q,t1));                else ans = min(ans , sum(x,y,p,q,t2));            }        }        if(get(-x,p))t1 = (-x) / p;        else t1 = (-x) / p + 1 ;        t = max(t1,t2);        ans = min(ans , sum(x,y,p,q,t));    }    return ans;}int main(){    int test;    // freopen("in.txt","r",stdin);    //freopen("out3.txt","w",stdout);    scanf("%d",&test);    while(test--)    {        LL a,b,A,B;        scanf("%lld%lld%lld%lld",&A,&B,&a,&b);        if(A > B)        {            LL p = A;            A = B;            B = p;        }        LL c = B - A;        printf("%lld\n",solve(a,b,c));    }}

原创粉丝点击