扩展欧几里德解二元一次不定方程

扩展欧几里得算法详见:@zhj5chengfeng
http://blog.csdn.net/zhjchengfeng5/article/details/7786595

对于二元一次不定方程: ax + by = c;

有解的充要条件是 : c % gcd(a,b) ==0;
可用扩展欧几里得算法求得 某一个解 x, 但不一定是最终解;
最终解应为X = x * c /gcd(a,b);
当然,此时 X 不一定是正数,可通过
X = ( X %(b/gcd(a,b)) + (b/gcd(a,b))) % (b/gcd(a,b));
来调整

应用例题:poj2115:
此题 容易推出 方程: (A + Cx)% 2^k = B;
即 Cx = (B-A) (mod 2^k) //(同余方程…)

再整理成 不定方程的形式就是: Cx + (2^k)y = (B-A)
然后 对应上面的解法 代入就 可以了。。。

代码

///poj2115
//Time; 16MS
//Memory: 724K
///编译器打三杠才清楚。。。请谅解

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long int LL;


LL ex_gcd(LL a, LL b, LL &x,LL &y)
{
    if(b==0)
    {
        x = 1;
        y = 0;
        return a;
    }

    LL ans = ex_gcd(b,a%b,x,y);
    LL temp = x;
    x = y;
    y = temp - a/b*y;

    return ans;
}




int main()
{
    LL A,B,C,k;
    while(cin>>A>>B>>C>>k)
    {
       if(!A&&!B&&!C&&!k) break;

       if(A==B) {cout<<"0"<<endl; continue;}

       LL M = (LL)1<<k;
    //cout<<M<<endl;

       LL G = B-A;

       ///方程: C*x + M*y = G ;


       LL x,y;
       LL ans = ex_gcd(C,M,x,y);
///ans == gcd(C,M);
       //cout<<ans<<endl;
       //cout<<G<<endl;
       if(G%ans != 0) {cout<<"FOREVER"<<endl; continue;}
///有解条件 G % gcd(C,M) == 0;


     //  cout<<x<<endl;  //一个解

       LL k = M/ans;  //

       LL ret =  x*G/ans;  ///最终解

       ret = (ret%(k) + (k))%k;  ///(调整)最终解,使之为可行的最小正整数

       cout<<ret<<endl;







    }


return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值