码迷,mamicode.com
首页 > 其他好文 > 详细

浅谈乘法逆元

时间:2019-02-10 09:38:03      阅读:206      评论:0      收藏:0      [点我收藏+]

标签:www   long   spl   表示   运算   logs   void   frame   结果   

一.定义

(及如何理解)

如果a*x≡1 (mod p),且gcd(a,p)=1(a与p互质),则称a关于模p的乘法逆元为x。(from Wikipedia)

a*x≡1 (mod p) 表示 a乘一个数x并模p等于1,即 a*x%p=1;看上去就是同余定理的一个简单等式。

而x 为 a 的逆元,记为x=a-1,所以我们也可以称 x 为 a 在mod b意义下的倒数,

什么意思呢? 可以理解为在x的倒数上加了个限定:

倒数定义为a*x=1,则x为a的倒数;

而逆元为:a*x%p=1;

 

用处:一般用于求 a/(mod p的值(p 通常为质数),是解决模意义下分数数值的必要手段。

    (比如某道水题让你对结果%p,而计算过程中有除法运算。。)

二.求解

1.扩展欧几里得算法求解逆元

  我们知道,a*x≡1 (mod p) 就是 a*x%p=1 也就是 a*x+p*y=1  

  而扩展欧几里得算法就是用来求线性同余方程a?xmod ),只不过此时c=1;

  

#include<cstdio>
#include<cmath>
#define R register int
#define ll long long
using namespace std;
int n,p;

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

int main()
{
    scanf("%d%d",&n,&p);
    for(R i=1;i<=n;i++)
    {
        ll x,y;
        ex_gcd(a,p,x,y);
        x=(x%p+p)%p;
        printf("%d\n",x);
    }
    return 0;
}

 

2.费马小定理和快速幂求解逆元

由费马小定理可知:ap-1≡1 (mod p)

所以a*ap-2≡1 (mod p)

即ap-2就是a在mod p意义下的逆元

#include<cstdio>
#include<iostream>
#include<cmath>
#define R register int 
#define ll long long 
using namespace std;

int n,p;

ll q_pow(ll x,ll ind,ll mod)
{
    x%=mod;
    ll a=1;
    for(;ind;ind>>=1,(x*=x)%=mod)
        if(ind&1) (a*=x)%=mod;
    return a;
}

int main()
{
    scanf("%d%d",&n,&p);
    for(R i=1;i<=n;i++) printf("%lld\n",q_pow(i,p-2,p));
    return 0;
}

3.O(n)的线性算法

  原题:P3811 【模板】乘法逆元 https://www.luogu.org/problemnew/show/P3811

  求 [1,n] 区间中每个数的逆元,其实这是一种递推。。。

  我们设 inv[i] 表示i的逆元,设 p=k*i+r (1<r<i<p) 可得:k*i+r≡0 (mod p)  (显然)

  则左右同乘 r-1 * i-1 :k*r-1+i-1≡0 (mod p)

  所以:i-1≡ -k*r-1 (mod p);

  易知:r-1=inv[p%i],k=p/i

  所以:i-1 = p/i * inv[p%i]

  而由逆元定义可知:inv[1]=1 (mod p),你就可以开始递推了。

  

#include<cstdio>
#include<iostream>
#define R register int 
using namespace std;
int n,p;
int inv[3000010];

int main()
{
    scanf("%d%d",&n,&p);
    inv[1]=1;printf("1\n");
    if(p>=2) for(R i=2;i<=n;i++) inv[i]=(long long)(p-p/i)*inv[p%i]%p,printf("%d\n",inv[i]);//话说记得用long long寄存,要不就死了。。。
    return 0;
}

 

4.阶乘逆元

。。。还未学会。。。安利一发zjp_shadow大佬的blog:https://www.cnblogs.com/zjp-shadow/p/7773566.html (写得太好了)

 

浅谈乘法逆元

标签:www   long   spl   表示   运算   logs   void   frame   结果   

原文地址:https://www.cnblogs.com/Jackpei/p/10358563.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!