51nod 1256 乘法逆元(扩展欧几里得算法)

 

思路1:把k*M%N=1可以写成一个不定方程,(k*M)%N=(N*x+1)%N,那么就是求k*M-N*x=1使得k最小,不定方程利用扩展欧几里得算法

--------------------------------------------------------------------------------------------------------------------------------

知识点:

  1. 扩展欧几里德算法是用来在已知a, b求解一组x,y,使它们满足贝祖等式: ax+by = gcd(a, b) =d(解一定存在,根据数论中的相关定理)。扩展欧几里德常用在求解模线性方程及方程组中。

2、ax+by=gcd(a,b);

设a>b

b=0时,gcd(a,b)=a.此时,x=1,y=0;

a>b>0,①:ax1+by1=gcd(a,b);②:bx2+(a mod b)y2=gcd( b , a mod b );第二个式子利用gcd的辗转相除法算法得到(gcd(a,b)=gcd(b,a mod b))。

然后将gcd左边两个等式列个等式:ax1+by1=bx2+(a mod b)y2;

a mod b可以写成a-(a/b)b,那么等式变成ax1+ by1= bx2+ (a - (a / b) * b)y2=bx2+ay2 - (a / b)by2 ;把ax1+ by1=bx2+ay2 - (a / b)by2拎出来,整理一下,写成:ax1+by1=ay2+b(x2-(a/b)y2); 可以得到,x1=y2,y1=x2-(a/b)y2;

这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于 x2,y2.对于算法里面x,y的由来我们这里就知道啦

3、扩展欧几里得算法用于除法取模(求逆元),关键是要求b、p互质( gcd(b, p) == 1)

设k为b的乘法逆元,则在求解除法取模问题时:

有(a/b)%p =>(a*k)%p

乘法逆元:

如果b*k ≡ 1 (mod p)即b*k%p=1,则称k是b关于p的乘法逆元

我们可以通过求 b 关于 p 的乘法逆元 k,将 a 乘上 k 再模 p,即 (a * k) mod p。其结果与(a / b) mod p等价。

证: 

因为 b * k ≡ 1 (mod p) 

则有 b * k = p* x+1 

得到 k = (p * x + 1) / b 

将 k 代入(a * k) mod p 

得到: 

(a * (p * x + 1) / b) mod p 

=((a * p * x) / b + a / b) mod p 

=[((a * p * x) / b) mod p +(a / b)] mod p 

=[(p * (a * x) / b) mod p +(a / b)] mod p 

=(0 + (a / b)) mod p 

= (a/b) mod p

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int ,int > P;
#define  Max  int(5e2+10)
#define INF 0xf3f3f3f
int n,m;
void Euild(int a, int b, int &x, int &y) { // x 是 a 关于 b 的乘法逆元
	if(0 == b) {
		x = 1, y = 0;
		return ;
	}
	Euild(b, a%b, x, y);
	int flag = x;
	x = y;
	y = flag - a/b * y;

}
int main() {
	scanf("%d%d",&m,&n);
	int x,y;
    Euild(m,-n,x,y);
    while(x<0)
    	x+=n;
	
    printf("%d\n",x);
}

思路2:

费马小定理表明一个数a的乘法逆元(关于m取模)等于a^(phi(m)-1).

phi(m)为m的欧拉函数值,显然当m为素数时phi(m)=m-1,即此时的乘法逆元为a^(m-2).

----------------------------------------------------------------------------------------------------------------------------

#include <iostream>

#include <cmath>

using namespace std;

typedef long long ll;

ll n;//模

ll m;

ll pow_mod(ll x,ll i)

{

    ll ans=1;

    while(i)

    {

        if(i&1)

            ans=(ans*x)%n;

        i>>=1;

        x=(x*x)%n;

    }

    return ans;

}

ll eular(ll a)

{

    ll ans=a;

    ll tmp=sqrt(a+0.5);

    for(ll i=2;i<=tmp;i++)

    {

        if(a==1)

            break;

        if(a%i==0)

        {

            ans=ans/i*(i-1);

            while(a%i==0)

                a/=i;

        }

    }

    if(a!=1)

        ans=ans/a*(a-1);

    return ans;

}

int main()

{

    ios::sync_with_stdio(false);

    while(cin>>m>>n)

    {

        cout<<pow_mod(m,eular(n)-1)%n<<endl;

    }

    return 0;

}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值