【总结】逆元的求法

2018-10-20  本文已影响0人  姜博钧

所谓一个数 a 的逆元,就是一个 x 使

a*x\equiv1(mod\ p)\ (p\in质数)

a*x\ mod\ p=0\ (p\in质数)

法一:快速幂(费马小定理)求逆元 \theta(log\ n)

由费马小定理得:
a^{p-1}\equiv1(mod\ p)\ (p\in质数)
那么将就可以将a^{p-1}拆成a*a^{p-2},得:
a*a^{p-2}\equiv1(mod\ p)
根据逆元的定义a^{p-2}就是a的逆元
然而a^{p-2}就可以用快速幂来求
source:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int mod = 19;
long long quickpow(long long a, long long b) {
    if (b < 0) return 0;
    long long ret = 1;
    a %= mod;
    while(b) {
        if (b & 1) ret = (ret * a) % mod;
        b >>= 1;
        a=(a*a) % mod;
    }
    return ret;
}
long long inv(long long a) {
    return quickpow(a, mod - 2);
}
int main(){
    long long a;
    scanf("%lld",&a);
    printf("%lld\n",inv(a));
    return 0;
}

法二:扩展欧几里得算法算法求逆元\theta(ln\ n)

根据上面对逆元的解释:a*x\ mod\ p=0\ (p\in质数)
利用扩展欧几里得算法:a*x+b*y=gcd(a,b)
那么对于数a的逆元就是用扩欧找到一个x使a*x=1
source:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long
void extend_gcd(ll a, ll b, ll &x, ll &y) {
    if (!b)
    {
        x = 1, y = 0;
        return;
    }
    else
    {
        extend_gcd(b, a % b, y, x);
        y -= x * (a / b);
        return;
    }
}
ll inv(ll a, ll n) {
    ll x, y;
    extend_gcd(a,n,x,y);
    x = (x % n + n) % n;
    return x;
}
int main(){
    ll a,p;
    scanf("%lld%lld",&a,&p);
    printf("%lld\n",inv(a,p));
    return 0;
}

法三:线性求1~p-1的逆元

以下公式都应该是在模p意义下的
因为
\lfloor\frac{p}{i}\rfloor*i=p-p\ mod\ i

\lfloor\frac{p}{i}\rfloor*i=-p\ mod\ i
挪一下再调个边
i^{-1}=(-p\ mod\ i)^{-1}*\lfloor\frac{p}{i}\rfloor
那么

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
int inv[1000];
int main(){
    int p;
    cin>>p;
    inv[1]=1;
    for(int i=2;i<p;i++) inv[i]=inv[p%i]*(p-p/i)%p;
    for(int i=1;i<p;i++) printf("%d ",inv[i]);
    printf("\n");
}

nia,这数学公式用的好爽!
参考博客:boshi 基本是抄的

上一篇 下一篇

猜你喜欢

热点阅读