数论c++ 同余(详细)

最近在学习算法,不管是算法竞赛中还是平常刷题中都绕不开数论,数论在算法中也是常考题了,但是我们平常在大学里一般没有这门课程,所以说学习这门课还是比较困难的,总不能跑到数学院中偷听把。今天我要分享的学习笔记的主题就是 同余 

目录

基本概念:

同余的性质:

不定方程:

裴蜀定理:

欧几里得算法:

扩展欧几里得算法:

同余定理:

​​​​​​​

基本概念:

在数学中,符号 "|" 表示整除关系。解释这两个表达式前,先了解一下符号定义:

a| b: 表示a 可以整除b。

如果 a|b  以及 b|a表示a与b相等 即a==b.

同余指的就是,有两个数,这两个数模以同一个数的结果是相同的,那么这两个数之间就有

一种关系,叫同余。用公式表示就是 a≡b(mod d)

同余的性质:

自反性:a ≡ a ( m o d m ) a≡a(mod \quad m)a≡a(modm)
对称性:a ≡ b ( m o d m ) ⇔ b ≡ a ( m o d m ) a≡b(mod \quad m)\Leftrightarrow b≡a(mod \quad m)a≡b(modm)⇔b≡a(modm)
传递性:a ≡ b ( m o d m ) 且 b ≡ c ( m o d m ) ⇒ a ≡ c ( m o d m ) a≡b(mod \quad m)且 b≡c(mod \quad m)\Rightarrow a≡c (mod \quad m)a≡b(modm)且b≡c(modm)⇒a≡c(modm)

同乘性:a≡b(modm)⇒na≡nb(modm)其中a为整数

同幂性:a≡b(modm)⇒an≡bn(modm)其中a为整数
原文链接:https://blog.csdn.net/weixin_43627118/article/details/103357784

不定方程:

不定方程,又称为丢番图方程,通俗的说就是多个未知数的方程,求解只在整数范围内进行。

比如: ax+by=c 的二元一次的不定方程。

裴蜀定理:

简单来说:只有等式右边是a和b的最大公约数或者最大公约数的倍数,x和y才有整数解

所以后面很多题都要转换成上方这种形式,然后再进行后续操作才可以。

欧几里得算法:

gcd(a,b)=gcd(b,a%b) (gcd(a,b)代表最大公约数)

这里比较重要,同过将求a,b的最大公约数先求其等价子问题b,a%b,因为取余会将这两个数越来越小,知道最后当b=0的时候,a就是答案

扩展欧几里得算法:

这里面的通解可能难以理解,以下是证明过程:

接下俩是一道例题,运用上方的扩展欧几里得算法:

 

#include<bits/stdc++.h>
using namespace std;
using ll= long long ;

ll ans;
ll exgcd(ll a,ll b,ll &x,ll &y){//注意这里是用&引用接收的x和y
    if(!b){//当b=0时,a就是最大公约数
        x=1;
        y=0;
        return a;
    }
    ll x1,y1;
    ans=exgcd(b,a%b,x1,y1);//向更深处递归,直到b=0
    x=y1;//   公式求解x和y
    y=x1-a/b*y1; 
    return ans;//这个返回的ans永远是最大公约数
}

int main(){
    ll n,m,x,y,l;
    cin>>x>>y>>m>>n>>l;//接收
    ll b=n-m,a=x-y;
    if(b<0){//保证a和b都是正的
        b=-b;
        a=-a;
    }
    ll x1,y1;
    exgcd(b,l,x1,y1);
    if(a%ans!=0){
        cout<<"Impossible";
    }else cout <<((x1*(a/ans))%(l/ans)+(l/ans))%(l/ans);//保证返回是正数
}

同余定理:

题:求关于 xx 的同余方程 ax≡1(modb) 的最小正整数解。

这种题应该如何解呢?

1.就是将同余方程转化为不定方程

由ax ≡ b (mod m) 得ax=m(-y)+b

即 ax+my=b

由裴蜀定理,当gcd(a,m)|b时有解

2.用扩欧算法  

求ax+my =gcd(a,m)的解,把x乘以b/gcd(a,m)即可得到原方程的特解

下方就是题和代码:203. 同余方程 - AcWing题库

#include<bits/stdc++.h>
#define int long long

using namespace std;
int exgcd(int a,int b,int& x,int& y){//这个就相当于模版了,背下来
    if (b==0){
        x=1,y=0;return a;
    }
    int x1,y1,d;
    d=exgcd(b,a%b,x1,y1);
    x=y1;
    y=x1-a/b*y1;
    return d;
}

signed main(){
    int a,b,x,y;
    cin>>a>>b;//接收数据
    exgcd(a,b,x,y);

    cout<<((x%b+b)%b);//不管x是否为正数还是负数,这样操作后一定是最小整数
    return 0; 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值