解线性同余方程的两种方法及其模板

定义:a,b是整数,形如ax≡b(mod m)ax≡b(mod m),且x是未知整数的同余式称为一元线性同余方程。

定理:a,b,m是整数且m>0,gcd(a,m)=dgcd(a,m)=d,如果d|b,则方程恰好有d个模m不同余的解,否则方程无解。

由同余方程的定义式可得ax+my=bax+my=b,这个方程称为二元一次不定方程。

  • 解一元线性同余方程

    设d=gcd(a,m),由定理可知若不满足d|b,那么方程无解;否则:

    a=d∗a0a=d∗a0

    m=d∗m0m=d∗m0

    那么方程变为:a0x+m0y=b/d(二元一次不定方程两边同除以d)a0x+m0y=b/d(二元一次不定方程两边同除以d)

    由于此时gcd(a0,m0)=1gcd(a0,m0)=1,因此可以运用扩展欧几里得算法得出方程a0x+m0y=b/da0x+m0y=b/d的解x(等价于a0x(b/d)+m0y(b/d)=1)(等价于a0x(b/d)+m0y(b/d)=1),

    虽然x不唯一,但是属于一个模m剩余系,由定理可知,共有d个模m剩余类满足方程,其代表分别为:(由a0x≡bd(mod m0)得到a0x≡bd(mod m0)得到)

    x,x+m0,x+2m0...x+(d−1)m0x,x+m0,x+2m0...x+(d−1)m0

  • 例题(POJ 1061青蛙的约会)

    • 题目大意

    在一个圆环上有两只青蛙A和B,从0点自东向西为正方向,两只青蛙的位置分别为x,y,A每次跳m,B每次跳n,环总长为L.两只青蛙同时出发,两只青蛙落在同一点视为相遇,问最少经过几次跳跃两只青蛙相遇。

    • 分析

    设k次相遇,则有x+mk≡y+nk(mod L)x+mk≡y+nk(mod L)

    转化成(m−n)k≡(y−x)(mod L)(m−n)k≡(y−x)(mod L)就变成了一个裸的线性同余方程的问题了

    • 代码
  • #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<cstdlib>
    #include<queue>
    using namespace std;
    typedef long long int LL;
    LL Gcd(LL a,LL b)
    {
        return b==0?a:Gcd(b,a%b);
    }
    LL Exgcd(LL a,LL b,LL &x,LL &y)
    {
          if(b==0)
          {
                x=1;
                y=0;
                return a;
          }
          else
          {
               LL ans=Exgcd(b,a%b,x,y);
               LL temp=x;
               x=y;
               y=temp-(a/b)*y;
               return ans;
          }
    }
    //这种写法方便理解
    LL f(LL a,LL b,LL m)//求解一元线性同余方程
    {
        LL x,y,d;
        LL a0,m0;
        d=Gcd(a,m);
        if(b%d!=0)return -1;
        a0=a/d;
        m0=m/d;
        Exgcd(a0,m0,x,y);
        x=x*b/d;
        x=(x%m0+m0)%m0;
        return x;
    }
    //这种写法更简洁
    LL f2(LL a,LL b,LL m)//求解一元线性同余方程
    {
        LL x,y,d;
        d=Exgcd(a,m,x,y);
        if(b%d!=0)return -1;
        x=x*(b/d)%m;
        x=(x%(m/d)+(m/d))%(m/d);
        return x;
    }
    int main()
    {
        LL x,y,m,n,L;
        LL A,B,C,xx,yy,d;
        while(scanf("%I64d %I64d %I64d %I64d %I64d",&x,&y,&m,&n,&L)!=EOF)
        {
            LL ans=f2(n-m,x-y,L);
            if(ans==-1)cout<<"Impossible"<<endl;
            else  cout<<ans<<endl;
        }
        return 0;
    }

    参考自https://blog.csdn.net/mmy1996/article/details/54988187

  • 感谢大佬!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值