【hiho一下-95】 扩展欧几里得算法

      例题是hiho的一道题:

      题目

      这道题主要用到了欧几里得扩展算法,并且求一下最小正整数解就好了,没什么特别的。不过,再次学习了一下欧几里得扩展算法,有了更深的理解。欧几里得扩展算法可以有两种形式:

      1. ax + by = c = bx +(a%b)y 证明很容易,根据欧几里得算法,设t=(a,b),a=k1*t, b=k2*t, (a%b)=k3*t,那么c也能表示成t的倍数,只要修改x和y,就一定能相等。

      2. a*t1(k-1) + b*t2(k-1) = t3(k-1)

          a*t1(k) + b*t2(k) = t3(k)

          a*t1(k+1) + b*t2(k+1) = t3(k+1)

          t3(k+1) = t3(k-1)%t3(k)

      只要一直迭代下去,直到t3(k+1)=0,那么t3(k)就是最小公约数。有人可能会迷惑,这个公约数是谁和谁的呢?那么如果我们设置t3(0)=a,t3(1)=b,那么就是(a,b),由此可以得到最初的两个式子:

      a*1 + b*0 = a

      a*0 + b*1 = b

      只要推理一下,就能得到递推公式:

      t3(k+1) = t3(k-1) % t3(k)

      t1(k+1) = t1(k-1) - t1(k)*tmp

      t2(k+1) = t2(k-1) - t2(k)*tmp

      tmp = t3(k-1)/t3(k)

      证明方法请自行百度一下:证明

      下面是题目的代码:

//
//  hiho.cpp
//  hiho
//
//  Created by lhq on 16/4/25.
//  Copyright © 2016年 lhq. All rights reserved.
//

#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;

/*
 ax + by = gcd = bx + a%by = bx + (a - a/b * b)y = ay + (x - a/b*y)b
 
 v1 > v2
 s1 + v1*t = s2+ v2*t - km
 (v1-v2)*t + mk = s2 - s1
 
 v2 > v1
 s2 + v2*t = s1 + v1*t -km
 (v2-v1)*t + km = s1 - s2
 
 at + mk = gcd
 求t,k   t,k > 0 且为整数
 
 ax + by = gcd
 a*(x + b/gcd * u)
 b*(y - a/gcd * u)
 
 求最小的x
 
 */

// ax + by = c  a = b , b = a%b 直到b = 0 主动改变a,b
long long gcd_ex(long long& x, long long& y, long long a, long long b){
    if(b == 0){
        x = 1;
        y = 0;
        return a;
    }
    long long tmp = gcd_ex(x, y, b, a%b);
    long long tmpy = y;
    y = x - (a/b)*y;
    x = tmpy;
    return tmp;
}

// at1 + bt2 = t3   t3 = t1%t2 直到t3=1 主动改变x,y  注意:初始值设置为,t3(k-1)=a, t3(k)=b,所以肯定能得到t3=(a,b)
long long gcd_ex_2(long long& x, long long& y, long long a, long long b){
    long long to_1,to_2,to_3;
    long long tm_1,tm_2,tm_3;
    long long tn_1,tn_2,tn_3;
    //不存在最大公约数
    if(a == 0 || b == 0){
        x = y = 0;
        return 0;
    }
    to_1 = 1; to_2 = 0; to_3 = a;
    tm_1 = 0; tm_2 = 1; tm_3 = b;
    for(tn_3 = to_3%tm_3; tn_3!=0; tn_3=to_3%tm_3){
        long long tmp = to_3 / tm_3;
        tn_1 = to_1 - tmp * tm_1;
        tn_2 = to_2 - tmp * tm_2;
        
        to_1 = tm_1; to_2 = tm_2; to_3 = tm_3;
        tm_1 = tn_1; tm_2 = tn_2; tm_3 = tn_3;
    }
    x = (tm_1%(b/tm_3) + b/tm_3)%(b/tm_3);   //最小正整数解
    y = (tm_2%(b/tm_3) + a/tm_3)%(a/tm_3);   //最小正整数解
    return tm_3;
}

int main(){
    long long s1,s2,v1,v2,m;
    long long x,y,a,b,c,gcd;
    while(cin>>s1>>s2>>v1>>v2>>m){
        a = (v1 - v2);
        b = m;
        c = (s2 - s1);
        if(a<0){
            a = -a; c = -c;
        }
        if(c<0){
            c += m;
        }
        gcd = gcd_ex_2(x, y, a, b);
//        gcd = gcd_ex(x, y, a, b);
        if(c % gcd){
            cout<<-1<<endl;
        }else{
            b = b/gcd;
            x = (x*c/gcd)%b;
            if(x>0){
                cout<<x<<endl;
            }else{
                while(x<0){
                    x += b;
                }
                cout<<x<<endl;
            }
        }
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值