gcd 和 同余方程(Exgcd)
时间:2019-08-18
本文章向大家介绍gcd 和 同余方程(Exgcd),主要包括gcd 和 同余方程(Exgcd)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
求关于x的同余方程 ax≡1(mod b) 的最小正整数解。
对于 100%的数据,2≤a,b≤2*109。
NOIP 2012 提高组 第二天 第一题
(只看Exgcd的自行跳过这段文字)
先撇开扩展欧几里得什么的不管,首先证明辗转相除法。
gcd(greatest common divisor),是一种计算两个数最大公约数的算法,时间复杂度为O(1)。简单来说,我们定义gcd(a,b)为a、b的最大公约数,那么gcd(a,b)=gcd(b,a mod b)。一般使用递归计算,在最后一层,a≡0(mod b)的时候,这一层的b即为答案。
下面给出证明:
令a>b,则存在正整数k、r,使得a=kb+r,而r≡a(mod b),所以我们要证明的结论就是gcd(a,b)=gcd(b,r)。
若r=0,那么以上结论显然。
那么,若r≠0呢?
假设gcd(a,b)=d,那么存在正整数p、q,使得a=pd,b=qd(p>q)。
所以pd=kqd+r,整理得r=(p-kq)d。因为r>0,所以pd>kqd,显然p-kq为正整数,所以r必为d的倍数,不难证明gcd(a,b)=gcd(b,r),也就是gcd(a,b)=gcd(b,a mod b)。
1 #include<bits/stdc++.h> 2 #define LL long long 3 using namespace std; 4 5 LL a,b;//不开long long见祖宗 6 7 LL gcd(LL a,LL b) 8 { 9 if(b==0) return a; 10 return gcd(b,a%b); 11 } 12 int main(){ 13 scanf("%d%d",&a,&b); 14 printf("%lld",gcd(a,b)); 15 return 0; 16 }
踏入正题~
问题是求解同余方程 ax≡1(mod b) 的最小正整数解。
将问题转化一下,这个方程的实质是ax+by=1(其中y为整数)。
扩欧求的是ax+by=gcd(a,b)的解。
那显然,这里的gcd(a,b)=1,所以这里a,b互质。
扩展欧几里得算法~前置知识:辗转相除法。
对于ax+by=gcd,输入中已经给了a、b我们只要求出一组x,y解,满足x是无数组解中最小的正整数。
假设我们求出了另一组数x2、y2,使得bx2+(a mod b)y2=gcd(b,a mod b),则因为gcd(a,b)=gcd(b,a mod b),所以bx2+(a mod b)y2=gcd(a,b);
联立等式,得到ax+by=bx2+(a mod b)y2。
我们可以将a mod b转化成a-(a/b)*b。
所以ax+by=bx2+(a-(a/b)*b)y2
ax+by=ay2-b(x2-(a/b)y2)
解得x=y2,y=x2−(a/b)y2。
对于等式bx2+(a mod b)y2=gcd(b,a mod b),我们再观察等式ax+by=gcd(a,b)。发现两个等式本质上是相同的,可得依次推出x3,y3,x4,y4……
直到最后一组b=0时,解得x=1,y=任意整数,当然,y最好取0,有可能会数值越界。
另外,x还要进行最后的处理,x=(x%b+b)%b就做到了x为最小正整数解,想想为什么?
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 5 int a,b,x,y; 6 7 void Exgcd(int a,int b) 8 { 9 if(b==0) 10 { 11 x=1,y=0;//最终的x、y 12 return; 13 } 14 Exgcd(b,a%b); 15 int tmp=x; 16 x=y;//更新上一层x 17 y=tmp-(a/b)*y;//更新上一层y 18 } 19 signed main()//main函数不能为long long 20 { 21 scanf("%lld%lld",&a,&b); 22 Exgcd(a,b); 23 x=(x%b+b)%b;//最小正整数解 24 cout<<x<<endl; 25 return 0; 26 }
数学题多手算模拟几遍就理解了~
原文地址:https://www.cnblogs.com/Darkring/p/11371094.html
- 手把手教你撸一个 Webpack Loader
- HashMap与HashTable区别
- iKcamp|基于Koa2搭建Node.js实战(含视频)☞ 记录日志
- React Native 网络层分析
- 如何实现VM框架中的数据绑定
- Java盲点解析
- iKcamp|基于Koa2搭建Node.js实战(含视频)☞ 解析JSON
- iKcamp|基于Koa2搭建Node.js实战(含视频)☞ 处理静态资源
- iKcamp|基于Koa2搭建Node.js实战(含视频)☞ 视图Nunjucks
- iKcamp|基于Koa2搭建Node.js实战(含视频)☞ 代码分层
- iKcamp|基于Koa2搭建Node.js实战(含视频)☞ HTTP请求
- ubuntu中安装tomcat
- python文件操作
- Owasp测试4.0手册
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法