逆元的定义,性质,求解方法与例题


一、定义

若整数a、b满足同余方程a∗b≡1(mod n) ,那么a,b互为模n意义下的逆元

逆元存在的充要条件为gcd(a,n)为1.


二、作用及证明

作用.计算除法的模 (a/b) mod n

除法不可以使用之前分部的策略,否则结果将会产生问题

证明:

1.若 ( a / b ) mod n = m,左右同时乘以 b
由于m 与(a/b)是关于模n同余的,
根据同余式的性质:
若a≡b (% p),则对于任意的c,都有
(a * c) ≡ (b * c) (%p)

所以此时有:
a % n = (m * b)% n
2.若存在x,可使得 a * x = m%n,将x与上式的左右相乘
根据相同的性质,得:
(a * x)% n = (m * x * b)% n = m % n
也就意味着 (b * x)%n = 1;
即 x,b互为模n意义下的逆元

那么证得通过a 乘上 b 对模n的逆元可以求出(a/b) mod n


三、求解方法

1.扩展欧几里得算法

扩展欧几里得算法
a ∗ x ≡ 1 ( mod n)
可以化为:a* x = k * n + 1
a * x + (-k )* n = 1
即 a * x + n * k = 1
满足扩展欧几里得的格式,若此时gcd (a,n)!=1,那么此时方程无解,即不存在逆元

若满足gcd (a,n)的条件,根据扩展欧几里得算法就可以直接求出一个x,当然此时的解也不唯一,不过我们一般都是使用exgcd所得的那个特解。
对exgcd所得的那个解进行处理,保证其为一个正整数。
x%mod+mod)%mod

typedef long long LL;
LL exgcd(LL a,LL b,LL &x,LL &y)//扩展欧几里得算法 
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    LL ret=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return ret;
}
LL getInv(int a,int mod)//求a在mod下的逆元,不存在逆元返回-1 
{
    LL x,y;
    LL d=exgcd(a,mod,x,y);
    return d==1?(x%mod+mod)%mod:-1;
}

2.欧拉定理与费马小定理(快速幂求法)

费马小定理:
若p为素数,则有a^(p-1) ≡ 1(mod p)

欧拉定理(费马小定理的推广):
若a、p互素,则有a^φ( p) ≡ 1(mod p)

两个定理的证明

在费马小定理中,a ^ (p-2)∗a ≡ 1(mod p)
a ^ (p-2)就是a在mod p意义下的逆元;

在欧拉定理中,a^(φ( p)-1)* a ≡ 1(mod p)
a^(φ( p)-1)就是a在mod p意义下的逆元

那么我们就转化为了求快速幂的问题。至于求欧拉函数的方法会在后面讲。

总之只要p为素数,就可以使用费马小定理直接快速幂求解;
若不为素数,就需要先求出p的欧拉函数再进行快速幂求解。

3.线性递推(逆元打表)

给定模 p 和 n,可以在线性时间内求出1 到 n 对 p 取模的逆元。

p为一个不算太大的质数

已知边界条件为 inv[ 1 ] = 1;
目标是求 i 模 p 的逆元
p 可以表示为 k * i + r;
其中存在关系:
k = p / i;
r = p % i;

根据 p = k * i + r
可以得到:( 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)
即inv[ i ] = (-k * inv[ r ] )(mod p)=(−p/i ∗ inv[p%i])(mod p)

此时我们就可以用inv[p%i] 的结果来计算inv[ i ]的结果。

void getInv(int mod)//线性递推求逆元 
{
    inv[1]=1;
    for(int i=2;i<mod;i++)
        inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}

四、性质(映射关系)

1.性质

当p为素数,则 1~p-1 的所有整数的 模p逆元 对应1~p-1的所有整数,既是单射也是满射。

例如,当p=7时,1~6 对应的 模7逆元 分别是 1,4,5,2,3,6

2.证明

在这里插入图片描述
至于a= 1 时,其逆元就是 1;
a = p-1 时,其逆元也为为p -1。


五、例题·瞬间移动

瞬间移动

1.分析

在这里插入图片描述

2.代码

#include<bits/stdc++.h>
using namespace std; 
typedef long long ll;
const int mod = 1000000007;
ll inv(long long a,long long m){//用递推直接求,不进行储存 
    if(a == 1)return 1;
    return inv(m%a,m)*(m-m/a)%m;
}
ll C(int a,int b){ //组合计算的快速方法
    ll t1=1,t2=1;
    for(int i = b ; i>=(b-a+1) ;i--)t1 = t1*i%mod;
    for(int i = a ; i>=1       ;i--)t2 = t2*i%mod;
    return t1*inv(t2,mod)%mod;
}
int main(){
   int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        if(n>m)swap(n,m);
        printf("%d\n", C(m-2,n+m-4) );
    }
    return 0;
}

  • 12
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值