zoukankan      html  css  js  c++  java
  • ZOJ

    题意:一个人在坐标A,要前往坐标B的位置。可以往左或往右走a,b,a+b个单位,求到达B的最小步数。

    分析:扩展欧几里得算法求解线性方程的套路不变。令C=fabs(A-B),c = a+b, 扩展gcd分别求 ax+by=C ; ax+cy = C : bx+cy = C的最小|x|+|y|。求min{|x|+|y|}需要一点思考。

    对于线性方程ax+by=c,设d = gcd(a,b) ,若方程有解,则必须d | c,特解为 (x0,y0) = ( xx*c/d,yy*c/d) 。设am = a/d, bm = b/d。

    此时方程的通解为 x = x0+ k*bm ; y = y0 - k*am。则需要求的是 res = min{ |x0 + k*bm| + |y0 - k*am| }。

    设直线L1:y1 = x0 + bm*k ; L2:y2 = y0 - am*k。

    则|y1|+|y2| 的最小值一定出现在y1=0或y2=0,即k1=-x0/bm 或 k2 = y0/am 时(数形结合),但由于k是整数,所以不一定y1、y2能取到0。所以枚举区间[-x0/bm-1, -x0/bm+1]和[y0/am -1 , y0/am +1]的 k 对应值中的最小值。

    #include<iostream>
    #include<stdio.h>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<cstring>
    using namespace std;
    typedef long long LL;
    const int maxn = 1e5+5;
    
    LL ABS(LL a)
    {
        return a>=0?a :-a;
    }
    
    LL Exgcd(LL a,LL b,LL &x,LL &y ) {
        if ( b == 0 ) {
            x = 1;
            y = 0;
            return a;
        }
        LL d = Exgcd(b, a%b, x, y), temp = x;
        x = y;
        y = temp-a/b*y;
        return d;
    }
    
    LL gao(LL a,LL b,LL c)          //ax+by=c
    {
        LL x,y;
        LL d = Exgcd(a,b,x,y);
        if(c%d)  return -1;
        LL am = a/d, bm = b/d;
        x *=c/d, y*= c/d;           //特解
        LL ans= ABS(x)+ABS(y);
        for(int i=-x/bm-1;i<=-x/bm+1;i++){
            LL X=x+bm*i;
            LL Y=y-am*i;
            if(i){
                LL tmp=ABS(X)+ABS(Y);
                if(tmp<ans) ans=tmp;
            }
        }
        for(int i=y/am-1;i<=y/am+1;i++){
            LL X=x+bm*i;
            LL Y=y-am*i;
            if(i){
                LL tmp=ABS(X)+ABS(Y);
                if(tmp<ans) ans=tmp;
            }
        }
        return ans;
    }   
    
    int main()
    {
        #ifndef ONLINE_JUDGE
            freopen("in.txt","r",stdin);
            freopen("out.txt","w",stdout);
        #endif
        LL a,b,A,B,k;
        int T; scanf("%d",&T);
        while(T--){
            scanf("%lld %lld %lld %lld",&A, &B, &a, &b);
            LL C = ABS(A-B),c = a+b;
            LL t1 =gao(a,b,C), t2 = gao(a,c,C) ,t3 = gao(b,c,C);
            if(t1==-1 && t2==-1 && t3==-1){
                puts("-1");
                continue;
            }
            LL ans=10000000000;
            if(t1!=-1) ans = min(t1,ans);
            if(t2!=-1) ans = min(t2,ans);
            if(t3!=-1) ans = min(t3,ans);
            printf("%lld
    ",ans);
        }
        return 0;
    }
    为了更好的明天
  • 相关阅读:
    如何解决加载动态链接库DLL失败,返回0,GetLastError返回错误码126
    如何实现点击激活窗体同时窗体不跑到最前覆盖其他窗体
    数据库04
    数据库03
    数据库02
    数据库01
    Linux02
    Linux01
    软件质量
    HTML04
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9511765.html
Copyright © 2011-2022 走看看