逆元概念及其求解方法

逆元

引出

存在取模运算公式:

(a + b) % c = (a % c + b % c) % c

(a * b) % c = (a % c * b % c) % c

(a - b) % c = (a % c - b % c + c) % c

但是不存在取模运算公式:

(a / b) % c = (a % c / b % c) % c

这时候逆元就出现了,逆元就是在mod下,不能直接除以一个数,而是要乘以它的逆元。

我们令inv(b)表示b的逆元,即inv(b) = b ^ -1

那么对于公式 (a / b) % c = (a % c / b % c) % c 我们可以写成乘法取模运算的形式,

可以转化成 (a * inv(b)) % c = (a % c * inv(b) % c) % c, 这样不就合法了。

逆元概念:

概念:

你元素是指一个可以取消另一给定元素运算的元素,在数学里,逆元素广义化了加法中的加法逆元和乘法中的倒数。

加法逆元:

对于一个数n, n和其加法逆元(或称相反数)之和是加法单位(即数字0)。

Eg:

8的加法逆元是-8

-0.5的加法逆元是0.5

乘法逆元:

对于任意的整数a,满足b|a(a能够被b整除),则存在一个整数x,使得 a / b ≡ a * x (mod p) 称 x 为 b 的模p 乘法逆元, x记为b ^ -1 (mod p)。

我们对于该同余等式 a / b ≡ a * x (mod p)进行化简:

两边同成b: a ≡ a * b * x (mod p)

两边同时除以a: 1 ≡ b * x (mod p)

化简结果为: b * x ≡ 1(mod p)

为了方便记我们就写成:ax ≡ 1 (mod p)

乘法逆元的充分必要条件以及求解方法:

我们在上述已经介绍了乘法逆元,即它的形式是: ax ≡ 1 (mod p)

那么什么时候这个同余等式是有解的呢?(即它的充分必要条件)

充分必要条件: a存在逆元的充分必要的条件是a与模数p互质。(互质数即两个或多个整数的公因数只有1的非零自然数)

求解方法:

对于p是否为质数,我们可以分成两种求乘法逆元的方法。

1)当p为质数,可以用快速幂求逆元(费马小定理)

由费马小定理可知,当p为质数时

a^(p - 1)≡ 1 (mod p)

拆出一个a来可得:a * a * (p - 2) ≡ 1 (mod p)

故当p为质数时,a的乘法逆元 x = a ^ (p - 2)

当然可能数p - 2很大,我们用快速幂来求解即可。

特例:

对于a是p的倍数的情况,其公约数时p,a和p肯定是不互质的,所以无解,即ax % p = 0

但是当a = 2, p = 2, a ^ (p - 2)= 2 ^(2 - 2) ≡ 1 mod(p)

因此对于a = 2 , p = 2 的情况需要特别判断一下(一般通过a % p == 0的方法判断掉)。

代码:

递归版(重复调用函数)

#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int INF = 1e9;
const int N = 1e5 + 5;
int n;
int a,b,p;
ll quick_mi(ll a,int b,int p){
    if(b==0)return 1;//指数可能会取到0
    if(b==1)return a%p;
    else if(b%2==1)return quick_mi((a*a)%p,b/2,p)*a%p;
    else if(b%2==0)return quick_mi((a*a)%p,b/2,p)%p;
}
int main()
{
    cin>>n;
    while(n--){
        cin>>a>>p;
        if(a%p!=0)cout<<quick_mi(a,p-2,p)<<endl;
        else cout<<"impossible"<<endl;
    }
    return 0;
}


迭代版(重复使用一个结构)

#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int INF = 1e9;
const int N = 1e5 + 5;
int n,a,p;
ll quick_mi(int a,int b,int p){
    ll res=1;
    while(b){
        if(b&1)res=res*a%p;
        a=a*(ll)a%p;
        b>>=1;
    }
    return res;
}
int main()
{
    cin>>n;
    while(n--){
        cin>>a>>p;
        if(a%p!=0)cout<<quick_mi(a,p-2,p)<<endl;
        else cout<<"impossible"<<endl;
    }
    return 0;
}

2)当p不为质数,可以用扩展欧几里得算法求逆元

由充分必要条件知,a有逆元的充要条件是a 与 p 互质,即 gcd(a, p) = 1

假设a的逆元为x,那么有a * x ≡ 1 (mod p)

等价: ax + py = 1

通过扩展欧几里得算法求解exgcd(a, p, x, y)即可。

你可能感兴趣的:(知识点整理,c++,线性代数,算法)