我是靠谱客的博主 和谐含羞草,最近开发中收集的这篇文章主要介绍扩展欧几里德与乘法逆元,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

扩展欧几里得:

扩展欧几里得是在欧几里得的基础上扩充而来:

 

gcd(a, b) = gcd(b, a mod b)

对于不全为 0 的非负整数 a、b,gcd(a,b)表示 a,b 的最大公约数,必然存在整数对 x,y ,使得 gcd(a,b)=ax+by。

 

 

 

就是给两个整数 a,b 必然存在一对整数 x,y 使得 ax + by = gcd(a,b),这个定理又叫贝祖定理。

证明:

假如 a > b, 且 b = 0,那么很明显, ax + by = ax + 0 = gcd(0, a mod 0) = a,也就是 x = 1。扩展欧几里德算法是成立的。

若a≠0 && b≠0,那么

设a*x1+b*y1 = gcd(a,b); 

那么 gcd(b,a mod b) = b*x2 + (a mod b) *y2;

因为gcd(a,b) = gcd(b,a mod b); 则 a * x1 + b * y1 = b * x2 + (a mod b) * y2;

然后化简:a % b = a - (int)(a/b) * b;

a * x1 + b * y1 = b * x2 + (a - (int)(a/b) * b) * y2
 

    a * x1 + b * y1 = b * x2 + a * y2 - (int)(a/b) * b * y2

    合并同类项

    a * x1 + b * y1 = a * y2 + b ( x2 - (int)(a/b) * y2 )

 得到结论:    x1 = y2

                      y1 = x2 - (int)(a/b) * y2。

 

 

int ex_gcd(int a,int b,int &x,int &y){
	if(b == 0){
		x = 1;
		y = 0;
		return a;
	}
	int ans = ex_gcd(b,a%b,x,y);
	int temp = x;
	x = y;                     //x1=y2;
	y = temp - a/b*y;          //y1 = x2-a/b*y2;
	return ans;
}

 

 

 

 

 

 

 

乘法逆元:(在维基百科中也叫倒数,当然是 mod p后的)

a ≡1mod(f) ;

 

就相当于求 a*x+f*y=1 , gcd(a,f) == 1时有解(a,f互素)。

 

 

 

例如:

4关于1模7的乘法逆元为多少?

4X≡1 mod 7

这个方程等价于求一个X和K,满足

4X=7K+1

其中X和K都是整数。

若ax≡1 mod f, 则称a关于模f的乘法逆元为x。也可表示为ax≡1(mod f)。

a与f互素(1=gcd())时,a关于模f的乘法逆元有解。(a*x+b*y=c,  c=gcd(a,b)是方程有解的充要条件)如果不互素,则无解。如果f为素数,则从1到f-1的任意数都与f互素,即在1到f-1之间都恰好有一个关于模f的乘法逆元。

int cal(int a,int m){
    int x,y;
    int gcd = ex_gcd(a,m,x,y);
    if( (1%gcd)!=0 ) return -1;
    x*=1/gcd;
    int ans = x%abs(m);
    if(ans<=0) ans+=m;
    return ans;
}

做题时如果结果过大一般都会让你模一个数,确保结果不是很大,而这个数一般是1e9+7,而且这个数又是个素数,加减乘与模运算的顺序交换不会影响结果,但是除法不行。有的题目要求结果mod一个大质数,如果原本的结果中有除法,比如除以a,那就可以乘以a的逆元替代。(除一个数等于乘它的倒数,虽然这里的逆元不完全是倒数,但可以这么理解,毕竟乘法逆元就是倒数的扩展)。

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

void exgcd(ll a,ll b,ll& d,ll& x,ll& y)
{
    if(!b) { d = a; x = 1; y = 0; }
    else{ exgcd(b, a%b, d, y, x); y -= x*(a/b); }
}

ll inv(ll a, ll p)
{
    ll d, x, y;
    exgcd(a, p, d, x, y);
    return d == 1 ? (x+p)%p : -1;
}

int main()
{
    ll a,p;
    while(1)
    {
        scanf("%lld %lld",&a,&p);
        printf("%lldn",inv(a,p));
    }
}

 

逆元线性筛:

const int mod = 1000000009;
const int maxn = 10005;
int inv[maxn];
inv[1] = 1;
for(int i = 2; i < 10000; i++)
    inv[i] = inv[mod % i] * (mod - mod / i) % mod;

阶乘的逆元:


inv[maxn]=mod_pow(fac[maxn],mod-2);
for(ll i=maxn-1;i>=0;i--)
    inv[i]=(inv[i+1]*(i+1))%mod;


3.费马小定理。

假如a是一个整数,p是一个质数,那么   a的p次方-a   是p的倍数,可以表示为




如果a不是p的倍数,这个定理也可以写成




由费马小定理 ap-1≡1 , 变形得 a*ap-2≡1(mod p),:若a,p互质,因为a*ap-2≡1(mod p)且a*x≡1(mod p),则x=ap-2(mod p),用快速幂可快速求之。
 

最后

以上就是和谐含羞草为你收集整理的扩展欧几里德与乘法逆元的全部内容,希望文章能够帮你解决扩展欧几里德与乘法逆元所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(40)

评论列表共有 0 条评论

立即
投稿
返回
顶部