欧几里得算法

求两个正整数 a 和 b 的 最大公约数 d
则有 gcd(a,b) = gcd(b,a%b)
证明
设a%b = a - kb 其中k = a/b(向下取整)
若d是(a,b)的公约数 则知 d|a 且 d|b 则易知 d|a-k
b 故d也是(b,a%b) 的公约数
若d是(b,a%b)的公约数 则知 d|b 且 d|a-kb 则 d|a-kb+k*b = d|a 故而d|b 故而 d也是(a,b)的公约数
因此(a,b)的公约数集合和(b,a%b)的公约数集合相同 所以他们的最大公约数也相同 证毕

欧几里得算法
利用gcd(a,b) = gcd(b,a%b)的性质,不断递归,直到b为0,那么a就是最大公约数。

ACWING872 最大公约数
给定 n 对正整数 ai,bi ,请你求出每对数的最大公约数。

输入格式
第一行包含整数 n 。

接下来 n 行,每行包含一个整数对 ai,bi 。

输出格式
输出共 n 行,每行输出一个整数对的最大公约数。

数据范围
1≤n≤10^5 ,
1≤ai,bi≤2×10^9
输入样例:

2
3 6
4 6

输出样例:

3
2
#include <bits/stdc++.h>
using namespace std;
int gcd(int a,int b)
{return b?gcd(b,a%b):a;
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);int n,a,b;cin>>n;while(n--){cin>>a>>b;cout<<gcd(a,b)<<'\n';}return 0;
}

扩展欧几里得算法

1.扩展欧几里得
用于求解方程 ax+by=gcd(a,b) 的解
当 b=0时 ax+by=aax+by=a 故而 x=1,y=0
当 b≠0 时
因为
gcd(a,b)=gcd(b,a%b)

bx′+(a%b)y′=gcd(b,a%b)
bx′+(a−⌊a/b⌋∗b)y′=gcd(b,a%b)
ay′+b(x′−⌊a/b⌋∗y′)=gcd(b,a%b)=gcd(a,b)
故而
x=y′,y=x′−⌊a/b⌋∗y′
因此可以采取递归算法 先求出下一层的x′和y′再利用上述公式回代即可
2.对于更一般的方程 ax+by=c
设 d=gcd(a,b) 则其有解当且仅当 d|c
求解方法如下:

用扩展欧几里得求出 ax0+by0=d的解

则a(x0∗c/d)+b(y0∗c/d)=c
故而特解为 x′=x0∗c/d,y′=y0∗c/d
而通解 = 特解 + 齐次解

而齐次解即为方程 ax+by=0ax+by=0的解

故而通解为 x=x′+k∗b/d,x=y′−k∗a/dk∈z
3.应用: 求解一次同余方程 ax≡b(modm)ax≡b(modm)
则等价于求

ax=m∗(−y)+b

ax+my=b

有解条件为 gcd(a,m)|b然后用扩展欧几里得求解即可

特别的 当 b=1 且 a与m互质时 则所求的x即为a的逆元

ACWING877扩展欧几里得算法
给定 n 对正整数 ai,bi ,对于每对数,求出一组 xi,yi ,使其满足 ai×xi+bi×yi=gcd(ai,bi) 。

输入格式
第一行包含整数 n 。

接下来 n 行,每行包含两个整数 ai,bi 。

输出格式
输出共 n 行,对于每组 ai,bi ,求出一组满足条件的 xi,yi ,每组结果占一行。

本题答案不唯一,输出任意满足条件的 xi,yi 均可。

数据范围
1≤n≤10^5 ,
1≤ai,bi≤2×10^9
输入样例:

2
4 6
8 18

输出样例:

-1 1
-2 1

AC代码:

#include <bits/stdc++.h>
using namespace std;
int exgcd(int a,int b,int &x,int &y)
{if(b==0){x=1,y=0;return a;}int gcd,x1,y1;gcd=exgcd(b,a%b,x1,y1);x=y1,y=x1-a/b*y1;return gcd;
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);int n,x,y,a,b;cin>>n;while(n--){cin>>a>>b;exgcd(a,b,x,y);cout<<x<<' '<<y<<'\n';}return 0;
}

注意点:这里用引用返回x和y的值

扩展欧几里得算法的应用1:线性同余方程

ACWING878 线性同余方程
给定 n 组数据 ai,bi,mi ,对于每组数求出一个 xi ,使其满足 ai×xi≡bi(modmi) ,如果无解则输出 impossible。

输入格式
第一行包含整数 n 。

接下来 n 行,每行包含一组数据 ai,bi,mi 。

输出格式
输出共 n 行,每组数据输出一个整数表示一个满足条件的 xi ,如果无解则输出 impossible。

每组数据结果占一行,结果可能不唯一,输出任意一个满足条件的结果均可。

输出答案必须在 int 范围之内。

数据范围
1≤n≤10^5 ,
1≤ai,bi,mi≤2×10^9
输入样例:

2
2 3 6
4 3 5

输出样例:

impossible
-3

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int exgcd(int a,int b,int &x,int &y)
{if(b==0){x=1,y=0;return a;}int gcd,x1,y1;gcd=exgcd(b,a%b,x1,y1);x=y1,y=x1-a/b*y1;return gcd;
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);int n,m,a,b,x,y;cin>>n;while(n--){cin>>a>>b>>m;int d=exgcd(a,m,x,y);if(b%d)cout<<"impossible"<<'\n';else{x=(LL)x*b/d%m;cout<<x<<'\n';}}return 0;
}

注意点:
// a * x ≡ b (mod m)
// 变形为拓展欧几里得形式:a * x + b * y = gcd(a, b)
// 原式变为: a * x = m * y + b (注:mod m 为 b, 则相当于结果为 m 的倍数和 b 的和)
// a * x - m * y = b
// 另y1 = -y得:a * x + m * y1 = b
// 根据拓展欧几里得定理,只要 b 是 gcd(a, m)的倍数即有解!
// 另d = gcd(a, m), 我们得到的式子其实是:a * x + m * y1 = gcd(a, m) = d (注;上面的b其实就是d的倍数)
// 所以左右同乘 b / d 即可转化为:a * x * b / d + m * y1 * b / d = d * b / d = b
// 即最后答案为:res = x * b / d % m

求逆元(快速幂、扩展欧几里得算法的应用)

当n为质数时,可以用快速幂求逆元:
a / b ≡ a * x (mod n)
两边同乘b可得 a ≡ a * b * x (mod n)
即 1 ≡ b * x (mod n)
同 b * x ≡ 1 (mod n)
由费马小定理可知,当n为质数时
b ^ (n - 1) ≡ 1 (mod n)
拆一个b出来可得 b * b ^ (n - 2) ≡ 1 (mod n)
故当n为质数时,b的乘法逆元 x = b ^ (n - 2)

当n不是质数时,可以用扩展欧几里得算法求逆元:
a有逆元的充要条件是a与p互质,所以gcd(a, p) = 1
假设a的逆元为x,那么有a * x ≡ 1 (mod p)
等价:ax + py = 1
exgcd(a, p, x, y)

ACWING876快速幂求逆元
给定 n 组 ai,pi ,其中 pi 是质数,求 ai 模 pi 的乘法逆元,若逆元不存在则输出 impossible。

注意:请返回在 0∼p−1 之间的逆元。

乘法逆元的定义
若整数 b,m 互质,并且对于任意的整数 a ,如果满足 b|a ,则存在一个整数 x ,使得 a/b≡a×x(modm) ,则称 x 为 b 的模 m 乘法逆元,记为 b^−1(modm)
b 存在乘法逆元的充要条件是 b 与模数 m 互质。当模数 m 为质数时, b^m−2 即为 b 的乘法逆元。

输入格式
第一行包含整数 n 。

接下来 n 行,每行包含一个数组 ai,pi ,数据保证 pi 是质数。

输出格式
输出共 n 行,每组数据输出一个结果,每个结果占一行。

若 ai 模 pi 的乘法逆元存在,则输出一个整数,表示逆元,否则输出 impossible。

数据范围
1≤n≤10^5 ,
1≤ai,pi≤2∗10^9
输入样例:

3
4 3
8 5
6 3

输出样例:

1
2
impossible

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL fp(int a,int b,int m)
{LL res=1;while(b){if(b&1)res=res*a%m;b>>=1;a=(LL)a*a%m;}return res;
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);int a,p,n;cin>>n;while(n--){cin>>a>>p;if(a%p==0)cout<<"impossible"<<'\n';else{cout<<fp(a,p-2,p)<<'\n';}}return 0;
}

注意点:

  • a%p==0不能写成!a%p,因为c++会把!和a绑定在一起,如果要用的话,记得加括号。
  • 因为p是质数,它与所有不是它倍数的数互质。因此,判断a与p互质只需要看a是不是p的倍数就行了。
  • 数学问题,一定要多用long long。

中国剩余定理

ACWING1298 曹冲养猪
自从曹冲搞定了大象以后,曹操就开始琢磨让儿子干些事业,于是派他到中原养猪场养猪,可是曹冲很不高兴,于是在工作中马马虎虎,有一次曹操想知道母猪的数量,于是曹冲想狠狠耍曹操一把。

举个例子,假如有 16 头母猪,如果建了 3 个猪圈,剩下 1 头猪就没有地方安家了;如果建造了 5 个猪圈,但是仍然有 1 头猪没有地方去;如果建造了 7 个猪圈,还有 2 头没有地方去。

你作为曹总的私人秘书理所当然要将准确的猪数报给曹总,你该怎么办?

输入格式
第一行包含一个整数 n ,表示建立猪圈的次数;

接下来 n 行,每行两个整数 ai,bi ,表示建立了 ai 个猪圈,有 bi 头猪没有去处。

你可以假定 ai,aj 互质。

输出格式
输出仅包含一个正整数,即为曹冲至少养猪的数目。

数据范围
1≤n≤10 ,
1≤bi≤ai≤1100000
所有 ai 的乘积不超过 10^18
输入样例:

3
3 1
5 1
7 2

输出样例:

16

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL m[12];
int a[12], b[12];
LL exgcd(LL a, LL b, LL &x, LL &y)
{if(b == 0){x = 1, y = 0;return a;}LL gcd, x1, y1;gcd = exgcd(b, a % b, x1, y1);x = y1, y = x1 - a / b * y1;return gcd;
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);int n;LL M = 1, res = 0;cin >> n;for(int i = 1; i <= n; i++){cin >> a[i] >> b[i];M *= a[i];}for(int i = 1; i <= n; i++){m[i] = M / a[i];LL x, y;exgcd(m[i], a[i], x, y);res += m[i] * x * b[i];}cout << ((res % M) + M) % M;return 0;
}

注意点:

  • 用long long
  • 最后的res有可能为负数(c++取余机制),所以要用((res % M) + M) % M把它变成正数。

扩展中国剩余定理

ACWING204 表达整数的奇怪方式
给定 2n 个整数 a1,a2,…,an 和 m1,m2,…,mn ,求一个最小的非负整数 x ,满足 ∀i∈[1,n],x≡mi(mod ai) 。

输入格式
第 1 行包含整数 n 。

第 2…n+1 行:每 i+1 行包含两个整数 ai 和 mi ,数之间用空格隔开。

输出格式
输出最小非负整数 x ,如果 x 不存在,则输出 −1 。
如果存在 x ,则数据保证 x 一定在 64 位整数范围内。

数据范围
1≤ai≤2^31−1 ,
0≤mi<ai
1≤n≤25
输入样例:

2
8 7
11 9

输出样例:

31

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL exgcd(LL a,LL b,LL &x,LL &y)
{if(b==0){x=1,y=0;return a;}LL gcd,x1,y1;gcd=exgcd(b,a%b,x1,y1);x=y1,y=x1-a/b*y1;return gcd;
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);int n;LL a1,a2,k1,k2,m1,m2,x;cin>>n;cin>>a1>>m1;n--;while(n--){cin>>a2>>m2;LL gcd=exgcd(a1,-a2,k1,k2);if((m2-m1)%gcd){//cout<<m2<<' '<<m1<<' '<<gcd<<'\n';x=-1;break;}k1*=(m2-m1)/gcd;LL t=abs(a2/gcd);k1=(k1%t+t)%t;m1=k1*a1+m1;a1=abs(a1/gcd*a2);}if(x!=-1)x=(m1%a1+a1)%a1;cout<<x;return 0;
}

注意点:

  • 由于不知道a1、a2的正负,所以lcm(a1,a2)和a2/d要加上绝对值
  • 记得LL和求余后取正的操作

欧几里得算法、扩展欧几里得算法、求逆元、中国剩余定理、扩展中国剩余定理相关推荐

  1. 扩展欧几里得算法求逆元c语言,关于扩展欧几里得算法和逆元

    关于扩展欧几里得算法和逆元 1.扩欧 a*x1+b*y1=gcd(a,b); b*x2+(a%b)*y2=gcd(b, (a%b))= gcd(a,b); a%b=a-(a/b)*b; 联立可得 x1 ...

  2. 扩展欧几里得算法、乘法逆元与中国剩余定理

    文章目录 前言 定义.定理和部分证明 整除 定义 定理 定理的证明 同余 定义 同余的性质 同余的运算律 运算律的证明 扩展欧几里得算法 代码模板 算法详解 乘法逆元 求解逆元 乘法逆元的作用 中国剩 ...

  3. 利用扩展欧几里得算法编程求逆元

    原理: 1.m是正整数,r属于Zm,且gcd(r,m)=1,存在s属于Zm,使得rs=1(mod m).则整数s称为r模整数m的乘法逆元. 2.对任意的两个整数a和b,总存在x和y使得gcd(a,b) ...

  4. 扩展欧几里得算法求逆元---乘法密码

    欧几里得算法 背景知识: 欧几里得算法:又叫做辗转相除法,用来求两个数的最大公约数.通过辗转相除,当余数为0的时候,最后的除数就是两个数的最大公约数. 例如:求20和11的最大公约数 每次将除数作为下 ...

  5. 扩展欧几里得算法(求逆元)

    扩展欧几里得算法(求逆元)总结 1.在RSA算法生成私钥的过程中涉及到了扩展欧几里得算法(简称exgcd),用来求解模的逆元. 2.首先引入逆元的概念: 逆元是模运算中的一个概念,我们通常说 A 是 ...

  6. 表格法轻松理解扩展欧几里得算法以及利用其求乘法逆元

    文章目录 扩展欧几里得算法 求乘法逆元 扩展欧几里得算法 具体算法的原理参见扩展欧几里得算法求乘法逆元,本文仅以表格的形式展现计算过程,浅显易懂.下面通过例子进行说明. 例:求1234和4321的最大 ...

  7. c语言中欧几里得模乘法逆元,扩展欧几里得算法同余方程模m乘法逆元详解

    欧几里德算法: 复习:求最大公约数算法(欧几里得算法.也叫辗转相除法).欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数. 基本算法:设a=qb+r,其中a,b,q,r都是整数,则gcd ...

  8. 【原创】更相减损术 stein算法 欧几里得算法 拓展欧几里得算法 扩展欧几里得算法 逆元的计算与筛法 解模线性方程

    欧几里得 说在前面 数论学复习 Part 6. 然后再来一章CRT和组合数,就飞往概率,以此为跳板去向DP. 计划很美啊你. P.S. 这么说来拉格朗日插值可以说是数论学复习的Part 0了啊. 有一 ...

  9. Python在GF(2⁸)有限域上求解多项式的乘法逆元——基于扩展欧几里得算法

    文章目录 一.前言 二.数学基础 1.GF(2⁸)有限域内的多项式 2.不可约多项式 3.多项式模运算 3.乘法逆元 三.算法步骤 1.扩展欧几里得算法 2.多项式除法 3.多项式乘法 四.代码实现 ...

  10. 乘法逆元、扩展欧几里得算法、二元一次方程、a的n次方取余

    知识点:乘法逆元,逆元的求法,二元一次方程求通解,a的n次方求余数 一,乘法逆元 乘法逆元的概念类似于倒数(ax=1,a−1=xax=1,a^{-1}=x),不过是在取余数的情况下的倒数. 如果(a× ...

最新文章

  1. 【Android 逆向】使用 DB Browser 查看并修改 SQLite 数据库 ( 从 Android 应用数据目录中拷贝数据库文件 | 使用 DB Browser 工具查看数据块文件 )
  2. 6kyu Steps in k-prime
  3. linux php和java环境变量配置_Linux下配置Java环境变量
  4. Python(37)_字典嵌套
  5. 将 nginx 安装成 windows 的方法
  6. c语言内部堆排序的实现,内部排序之堆排序的实现详解
  7. shell之旅--将目录下的文件重命名为md5码+后缀名
  8. c++中delete和析构函数之间的区别
  9. java查看jar包依赖_java项目开发中如何查找到项目依赖的jar包?
  10. CSS好看的一些颜色
  11. 论如何拯救程序员的发际线?程序员的事情当然要用编程解决啦
  12. 截图神器FastStone Capture :小而强悍的截图一哥 (软件-神器系列第1篇)
  13. cmd、conhost退居二线,Win 11将设置默认终端
  14. 疯狂动物城 zootopia
  15. 阿里-----数组四等分
  16. Linux 快速入门到实战【一】
  17. Fin- SAP Concur体验报告
  18. 13个整合营销的基本理论
  19. 如何使用Globus从NCAR官网上下载JRA55数据
  20. 【自制】基于QT5的简化版黄金矿工的实现

热门文章

  1. Java NIO 详解(一)
  2. Docker系列教程27-在生产环境中使用Docker Compose
  3. 0903 - Firebase Analytics PK Google Analytics
  4. 关于java.lang.ClassNotFoundException
  5. Weblogic配置和部署
  6. 常用jar包之commons-collection使用
  7. kafka如何确定分区数
  8. 2020-09-30
  9. 严重: Servlet.service() for servlet [taotao-manager] in context with path [] threw exception [Request
  10. 使用Go构建区块链 第3部分:持久化和cli