扩展Euclidean算法及其应用(乘法逆元,模线性方程)
来源:互联网 发布:用telnet测试端口 编辑:程序博客网 时间:2024/05/20 09:44
提到Euclidean算法就必须先讲一讲经典的求最大公约数算法
欧几里德算法又称辗转相除法,用于计算两个正整数a,b的最大公约数。——来自百度百科。
Euclidean算法求两个正整数a和b的gcd。先令r0为a,r1为b,接着执行如下运算:
使用gcd(a,b)表示a与b的最大公约数,则使用欧几里德算法求取最大公约数的实现代码如下:
//Euclidean算法求gcdint gcd( int a, int b ) { return b == 0 ? a : gcd( b, a%b );}
同时最小公倍数可通过以下代码实现:
lcm( a, b ) = a / gcd( a, b ) * b;
定理:对于不完全为0的非负整数a,b,gcd(a,b)表示a,b的最大公约数d,必然存在整数对x,y
使得gcd(a,b)=d=ax+by。
对于gcd(a,b) = d,对(a, b)用欧几里德辗转相除会最终得到(d, 0)。此时对于把a =d, b = 0代入a*x + b*y = d,显然x = 1,y可以为任意值。
我们可以用a = d, b = 0的情况逆推出来任何gcd(a, b) = d 满足a*x + b*y = d的解。如果x0,y0是b*x + (a%b)*y = d 的解,那么对于a*x + b*y = d的解呢?
b*x + (a%b)*y = d →
b*x + (a - [a/b]*b)*y = d →
a*y + b*(x - [a/b]*y)= d
所以a*x + b*y =d的解
x1 = y0,y1= x0 -[a/b]*y0;
由以上过程可以得出扩展欧几里德算法执行过程:
//扩展欧几里德算法int exgcd( int a, int b, int& x, int& y ) { if( b == 0 ) { x = 1; y = 0; return a; } int ret = exgcd( b, a % b, x, y ); int tmp = x; x = y; y = tmp - a / b * y; //y = ( ( tmp - a / b * y ) % mod + mod ) % mod; return ret;}//获取gcd(a,b)=ax+by中的x,y的值
接下来介绍乘法逆元:
若m≥1,(a,m)=1,则存在c使得 ca≡1(mod m) 我们把c称为是a对模m的逆,记为 a-1(mod m)或a-1 可以用扩展欧几里德算法求a-1
应用: 求(a/b)%c时,若a为大整数时可以写成 (a%c)*b-1
还可以使用扩展欧几里德算法求乘法逆元:
/*******************************************扩展欧几里得算法求乘法逆元调用:exgcd( a, b, x, y );则: x为a模b的乘法逆元,y为b模a的乘法逆元********************************************/下面通过一个例子来详细介绍该怎么用扩展欧几里得算法求乘法逆元:
hdoj1576
题目要求给定两个数A和B,去求(A/B)%9973(由于A太大,故只给出n(n=A%9973) ),就是一个求B的乘法逆元的裸题,直接上代码:
/***********************OJ: HDOJID: foreverTASK: 1576.A/BLANG: C++NOTE: exgcd求乘法逆元***********************/#include <cstdio>#define mod 9973int exgcd( int a, int b, int& x, int& y ) { if( b == 0 ) { x = 1; y = 0; return a; } int ret = exgcd( b, a % b, x, y ); int tmp = x % mod; x = y % mod; y = ( ( tmp - a / b * y ) % mod + mod ) % mod; return ret;}int main(){ int t, n, b; scanf( "%d", &t ); while( t -- ) { scanf( "%d%d", &n, &b ); int x, y; x = y = 0; int ret = exgcd( b, mod, x, y ); printf( "%d\n", ( x * n ) % mod ); }}
最后再介绍模线性方程的求解:
定理:方程ax=b(mod n)对于未知量x有解,当且仅当gcd(a, n)|b
定理:方程ax=b(mod n)或者对模n有d个不同的解,其中d=gcd(a, n)或者无解。
定理:设d=gcd(a, n),假定对整数x’和y’,有d=ax’+ny’。如果d|b,则方程ax=b(modn)有一个解的值为x0,满足x0=x’(b/d)mod n。
定理:假设方程ax=b(mod n)有解(即有d|b,其中d=gcd(a, n)),x0是该方程的任意一个解,则该方程对模n恰有d个不同的解,分别为:xi=x0+i(n/d)(i = 1, 2, …, d-1)。
例:POJ2115
/*OJ: POJID: 3013216109TASK: 2115.C LooooopsLANG: C++NOTE: exgcd求解模线性方程*/#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#define ll __int64using namespace std;ll mod;ll exgcd( ll a,ll b,ll& x,ll & y ) { if( b == 0 ) { x = 1; y = 0; return a; } ll ret = exgcd( b, a % b, x, y ); ll tmp = x % mod; x = y % mod; y = ( ( tmp - a / b * y ) % mod + mod ) % mod; return ret;}int main(){ ll a, b, c, x, y; ll k; while( scanf( "%I64d%I64d%I64d%I64d", &a,&b,&c,&k) ) { if( a == 0 && b == 0 && c == 0 && k == 0) break; mod = (ll)1 << k; ll temp = ( ( b - a) % mod + mod ) % mod; x = y = 0; ll ret = exgcd( c, mod, x, y ); if( temp % ret == 0) { x = ( x * ( temp / ret ) ) % mod; x = ( x % ( mod / ret ) + mod / ret ) % ( mod / ret ); printf( "%I64d\n", x ); } else puts( "FOREVER" ); } return 0;}
0 0
- 扩展Euclidean算法及其应用(乘法逆元,模线性方程)
- 扩展欧几里德算法求乘法逆元(C语言版)
- 51nod 1256 乘法逆元(扩展欧几里得算法)
- 扩展欧几里得算法求乘法逆元
- pku1061(扩展欧几里德算法,中国剩余定理,模线性方程)
- POJ2115 (扩展欧几里得算法解模线性方程)
- 欧几里德算法、扩展欧几里德算法、乘法逆元
- 扩展欧几里得、求乘法逆元及其应用、中国剩余定理(互质版和非互质版)、欧拉函数、快速判素数模板
- 扩展欧几里得(乘法逆元)
- POJ2115 扩展欧几里德算法求解模线性方程
- 扩展欧几里得算法求解模线性方程
- 扩展的欧几里德算法求乘法逆元
- 用扩展欧几里德算法来求乘法逆元(…
- 扩展的欧几里德算法求乘法逆元
- 扩展欧几里德算法详解以及乘法逆元
- 【专题】欧几里得算法、扩展欧几里得、乘法逆元
- 扩展欧几里德算法计算乘法逆元详解
- 扩展欧几里得算法及其应用,逆元简介,中国剩余定理简介
- Android 那些你所不知道的Bitmap对象详解
- Ubuntu中查找与Launcher图标所对应的命令
- loadrunner启动web tour-Could not open port 1080-Port is already used by another server
- JavaScript中的this(你不知道的JavaScript)
- fork()子进程与父进程之间的文件描述符问题 www.educity.cn/linux/1241859.html
- 扩展Euclidean算法及其应用(乘法逆元,模线性方程)
- python递归创建目录
- 【数论】hdu4910Problem about GCD
- 极客班GeekBand - C++第一次课程辅导 - 李建忠
- Android 解决mac无法识别手机设备
- UVa 294 - Divisors(唯一分解)
- c++实现哈希表
- 关于C和C++中的基本数据类型int、long、long long、float、double、char、string的大小及表示范围
- 关于Java与c++隐藏、重写不同实现机制的探讨