逆元知识普及(扫盲篇) —— from Judge

本文详细介绍了数论中的逆元概念及其求法,包括蒙哥马利快速幂模、扩展欧几里得算法及线性推逆元三种方法。通过实例讲解了如何利用这些方法求解逆元问题。

 

watch out

本文是博主的 csdn 上搬过来的,格式有点崩,看不下去的可以去 博主的 csdn 上看(上面 格式会好很多,并且有些公式也用 $\LaTeX$  update 上去了,但是博主也在 cnblogs 上更新了一下...lateX 都用上了,应该不至于不能看)

 

 

最近有点颓废啊,写篇blog振作一下…(不过没图的数论blog真是不对我胃口)

emmm …首先介绍一下这是一篇关于数论中较为重要 (主要可能经常要用到) 的一个知识分支—逆元
相信你听到数论之后可能鼠标就想往网页上的 X 键上移了,但是还是劝你看一看, 总能有点收获的吧
(反正我觉得自己讲的相对网上其他 blog 还算是蛮清楚的了)

解释一下逆元:

首先同学们小学的时候都学过除法吧(这个问题有点奇怪,滑稽)?
那么你一定知道,“除以一个数等同于乘以这个数的倒数”对吧?
所以逆元是什么东西呢? 首先这里有个式子: $({a\over b}) \% p$,这个式子的答案怎么求?
没错,暴力求是一种方法,但是当 $b$ 非常大的时候呢 ? 这个时候就要用到逆元了

这里有一句口诀 “除以一个数再取模等同于乘以这个数的逆元再取模 ”(自创) 
什么意思? 设 $inv[b]$ 是 $b$ 的逆元, 那么 $({a\over b}) \%p = (a*inv[b]) \%p$  
这下就你能大概理解逆元是个什么东西(以及它大概是用来干什么的)了吧 ?

那么逆元怎么求 ? 首先这里得纠正一点, 我们不能直接说一个数的逆元是多少,
应该这么说: 一个数 $x$ 在模 $p$ 的条件下的逆元是多少.(这点概念还是蛮重要的)
其次,我们不难得知一个数的逆元有无穷多个,但是我们只需要求得一个数的最小正整数逆元就行了

另外,一个数 $x$ 在模 $p$ 的条件下不一定有逆元, $x$ 关于 $p$ 的逆元存在 当且仅当 $x$ 和 $p$ 互质
这里有一个推导: (设 $a$ 为 $x$ 的逆元, $b$ 为任意整数)

 

 


$x * a ≡ 1 (mod\ p)$ = 将p连入式子=> $x*a = 1 -b*p$ => $x*a+b*p=1$

那么我们就得到了一组新方程: $x*a+b*p=1$ 若$x$ 和 $p$不互质, 则 $x$和 $p$ 存在公约数 $d=gcd(x,p)>1$

提取出$d$, 得到: $d(x/d*a+p/d*b) = 1$ 移项得到: $(x/d * a+ p/d *b) = 1/d$

易知 $x$ , $p$ 能整除 $d$, 所以括号内定为整数, 又因为$d > 1$ ,等式右边必为真分数, 等式无解

证毕

 

 

 

那么说了半天,逆元到底怎么求呢 ? 别着急,往下看—-
求逆元有好几种方法, 但是在这里我们只讨论两种方法(一个偷懒用的 ,一个不容易翻车的),
不过在此之前我们先来讲讲费马小定理 (别害怕,这玩意儿知道怎么用就好,不会叫你推的)

这是费马小定理的原始状态: $a^p ≡ a (mod\ p)$ ,其中 $a$ , $p$ 互质 [感性理解一下 a 一直乘 a  会出现循环节,而循环节必然是 p-1 的因数,所以乘着乘着就变回来了]
然后, 原式 =移项 => $a^p - a ≡0 (mod\ p) $=提取 a => $a*(a^{p-1} - 1) ≡0 (mod\ p)$  
=两边同除以 a => $a^{p-1}-1 ≡0 (mod\ p)$ =再次移项 => $a^{p-1} ≡1 (mod\ p)$ 
于是 费马小定理的结论就产生了(注意,这个结论很重要),求逆元时经常要用(主要偷懒求逆元时必用)


好了,现在我们再来考虑逆元的求法

一、 蒙哥马利快速幂模(偷懒求逆元大法):

首先听到这么高大上(主要是长)的名字,相信你的内心一定是崩溃的,仿佛见到了高斯定理或者欧拉定理一样(别着急啊,扩欧等下才讲)
但其实蒙哥马利快速模这个算法并没有那么高大上,它的局限性很大,只有在 $p$ 是质数的情况下才可以使用
首先我们设 $inv(a)$ 是 $a$ 的逆元 那么根据定义, $inv(a) * a ≡1 (mod\ p)$ 
再根据 费马小定理 $a^{p-1} ≡1$ , 易得 $inv(a) * a ≡a^{p-1} (mod\ p)$ 
移项,得: $inv(a) ≡ a^{p-2}$ 
于是我们得到了快速幂模算法的一个前提条件: $inv(a) ≡ a^{p-2} (mod\ p)$

下面附上代码(自己即兴手打):
[这里是位运算处理的方法,当然也有递归求的方法,那个代码短一些,不过这个代码我打的顺手]

 

 //by Judge
 inline ll quick_pow(ll x,rint p){
    ll res=1;
    while(p){
        if(p&1) res=(res*x)%mod;
        x=(x*x)%mod, p>>=1;
    }
    return res;
 }
 inline inv(ll a){
     inv_a=quick_pow(a,mod-2);
     return inv_a;
 }

 

 

下面我们不着急讲第二种算法,先来讲讲这种快速模算法的应用:
求 $C(n,r) \% p$ 的值 , 其中 $p$ 是大质数(如$1e9+7$) ,那么最后的答案是: 原式 = $n! * (r! * (n-r)!)^{p-2} \%p$(也就相当于 ${n!\over r! *(n-r)!} \% p$ ,就是加了逆元)

推导过程:

 

$C(n,r) (mod\ p) = {n! \over r! * (n-r)!} (mod\ p)$=多乘一个 1 => $ {n! \over r! * (n-r)!} * 1 (mod\ p)$ ----1式

∵ p是质数,再根据费马小定理可得: $(r! * (n-r)!)^(p-1) ≡1 (mod\ p)$ ----2式

再将2式带入1式中得到: $ C(n,r) ≡ {n! \over r! * (n-r)!} * (r! *(n-r)!)^{p-1} (mod\ p) 指数相消得到 $C(n,r) ≡n! * (r! * (n-r)!)^{p-2} (mod\ p)$

 

其实换元一下推导会简洁得多...

令 tmp = r! * (n-r)! ,那么有:

$C(n,r)%p = ( n! / tmp ) \%p = ( n! / tmp ) * 1 \%p $

= $( n! * tmp^{-1} ) * tmp^{p-1} \%p$

= $( n! * tmp^{p-2} ) \%p$ = 上述的式子

 

关于费马小定理的清奇证明可以看这里

不过呢,博主好像有写过费马小定理的花式证明,在这里

代码实现:
 //by Judge
 #define ll long long
 const ll mod=; //1e9+7或者其他题目给定的大质数
 inline ll quick_pow(ll x,rint p){
    ll res=1;
    while(p){
        if(p&1) res=(res*x)%mod;
        x=(x*x)%mod, p>>=1;
    }
    return res;
 }
 inline C_mod(rint n,rint m){
    ll a=1,b=1;
    for(rint i=2;i<=n<<1;++i)
        a=(a*i)%mod;
    for(rint i=2;i<=m;++i)
        b=(b*i)%mod;
    for(rint i=2;i<=n-m;++i)
        b=(b*i)%mod;
    return (a*quick_pow(b,mod-2))%mod;
 }

 

 

然后您可以试试用这个算法 A 掉乘法逆元的模板题(放心没坑,只会T而已,要A的话得用线性推逆元):P3811 【模板】乘法逆元

 

 


然后是上文提到过的扩欧

二、扩展欧几里得算法(一般我们都讲扩欧) :

这个东西讲起来真是烦,一开始我还一直以为扩欧就是在求逆元…其实扩欧是求同余方程的解…
首先如果你不是萌新的话,那么你应该看到过ex_gcd这样(恶心)的字眼,
这玩意儿其实是扩欧…(ex 表示扩展, gcd 最大公约数是可以用欧拉求的嘛)

不废话了,进入正题, 首先扩欧公式如下: $ax+by = (a,b)$   [注意这里是等于]
[$(a,b)$ 代表 $gcd(a,b)$ ,$ a$ 和 $b$ 是已知数, 要求的是 $x$ 和 $y$ 的一组解]
那么很容易可以知道, 当 a 和 b 互质的情况下,原来的等式就变成了: $ax+by = 1$  
然后我们怎么用这玩意儿求逆元呢? 我们先考虑求逆元的式子: $a * inv[a] ≡1 (mod\ p)$ 
其中$inv[a]$ 同上表示 $a$ 的逆元, 现在我们令 $x = inv[a] , b = p$;
那么同余的式子就成了: $ax ≡1 (mod b)$ , 然后我们把 $b$ 加入式子中,就成了这样:
$ax+by = 1$ (这里我就不慢慢推了,看博客也是要动动脑子的嘛 )其中 $y$ 和 $x$ 一样,也是未知数
emmmm还是讲讲, $ax ≡1 (mod b)$ => $ax = by+1$ (然后就把同余去掉了,变成了等式)
移项 => $ax+by = 1$ (由于 $y$ 是不确定的,而且我们求的主要是 $x$ 所以 $y$ 的正负性没什么影响)

这样你应该就能看懂了, 扩欧公式中求解的 $x$ 就是 $a$ 的逆元(一切好像都非常的显然了)
ok, 我还是没有讲 扩欧中的 $x$ 和 $y$ 怎么解 (这个才是真正麻烦的地方,解释起来很麻烦) 对吧?
哎, 式子先列出来再说, 我再斟酌斟酌…

$ax+by =(a,b) =1 , bX+(a\%b)Y =(b,a\%b) =1$ (注意大小写,并且显然这里要满足 $a$  $b$ 互质的条件)
=> ………… => $x=Y , y=X-\lfloor {a\over  b}\rfloor*Y$ (其中 $X$ 和 $Y$ 已知)
好了,自己推导吧! (试图想混过去的样子) 咳咳… 首先 $ax+by = bX+(a\%b)Y$ 对吧? (两式合并)
然后我们把 $a\%b$ 转化一下,变成: $ax+by = bX+(a-b*\lfloor{ a\over b} \rfloor ) Y$ (其实就是用了模的定义式)
=> $ax+by = bX+aY-b* \lfloor{ a\over b} \rfloor Y$ =提取公因式 a,b => $a(x-Y) = b(X- \lfloor {a\over b}\rfloor Y-y) $

那么很显然, 我们令 $x = Y$ , 令 $y = X-\lfloor{ a\over b} \rfloor Y$ 就能轻松的构造出一组 x 和 y 的解了

然而现在又出现了一个问题: X 和 Y 怎么求? 其实我们同上的方法求出 X 和 Y 就行了:
$bX+(a\%b)Y=(a\%b)X’ + (b\%(a\%b))Y’$ 如果你还不能理解, 那么我们令 $p = b$, $q = a\%b$ ,
那么原式 => $pX+qY=qX’+(p%q)Y’$ 这不就和之前的式子差不多了吗?
现在你应该很容易就能看出来这是在用递归的方法求解原式的解

但是递归总是有有边界的,不能永远递归下去对吧(非常显然)
那么这个递归式子的边界是什么呢? emmmm 提示一下, 这个边界和 gcd 的边界有点关系
对, 边界就是 b 等于 0 的时候, 我们不能再递归下去了,那么原式就成了:
$1x+0y=1$ [a此时为 $(a,b)$ ,b为 0 ] 这应该很好解吧? 我们令 $x=1$,$y=0$ 就行了(y=0是为了…方便嘛)

然后递归求解同上,下面附上代码(也是即兴手打的)
[下面常规版的,偷懒版和这个其实本质上没有区别,只是简化了一下代码,那么这里就不附上了,有兴趣的同学可以自行百度]

//by Judge
#define ll long long
const int mod=; //同上
 void ex_gcd(ll a,ll b,ll &x,ll &y){
    if(!b){ x=1,y=0; return ; }
    ex_gcd(b,a%b,x,y);
    ll t=x; x=y,y=t-(a/b)*y;
 }
 //当然你也可以这么写,更能体现公式: 
 //  ll X=x,Y=y;
 //  x=Y,y=X-(a/b)*Y;
 inline ll inv(ll a){
    ll inv_a,y;
    ex_gcd(a,mod,inv_a,y);
    return inv_a;
 }

 

 

 

另外这里补充一下线性推逆元的方法 ($inv[i]$ 表示 $i$ 的逆元 , $fac[i]$ 表示 $i$ 的阶乘 , $p$为模数)

三、线性推逆元

1.求 1! ~ n! 的逆元:(因为我觉的阶乘的逆元反倒比较好推所以就先讲)

公式: $inv[i] ≡inv[i+1]*(i+1) (mod\ p)$
推导过程:

$fac[i] * inv[i] ≡1 (mod\ p)$

$fac[i+1] * inv[i+1] ≡1 (mod\ p) => fac[i]* (i+1) * inv[i+1] ≡1(mod\ p)$

由 同余的除法原理可得 : $inv[i] ≡inv[i+1] * (i+1)$

推导完毕

 

inline void get_finv(){
    fac[1]=finv[0]=1;
    for(int i=2;i<=n;++i;++i)
        fac[i]=fac[i-1]*i%mod;
    finv[n]=quick_pow(fac[n],mod-2);
    for(int i=n-1;i;--i)
        finv[i]=finv[i+1]*(i+1)%mod;
}

 

 

2.求 1 ~ n 的逆元(这个还稍微麻烦些)

公式:$inv[i] ≡inv[p%i] * (- p/i) (mod\ p)$
推导过程:

令 $s = p/i , t = p\%i$ , 则有:

$s*i + t = p$ (显然)

然后 $s*i + t ≡ 0 (mod\ p)$

移项得 $t ≡ -s*i (mod\ p)$

同除以 $t * i 得 t / (t*i) ≡ -s*i / (t*i) (mod\ p)$

将除法转化为乘法 => $inv[i] ≡ -s * inv[t] (mod\ p)$

于是将 $s=p/i , t=p\%i$ 带入就可以得到:

$$inv[i] ≡ inv[p\%i] * (-p/i) (mod\ p)$$

推导完毕

代码:

 

inline void get_inv(){
    inv[0]=inv[1]=1;
    for(int i=2;i<=n;++i)
        inv[i]=inv[mod%i]*(mod-mod/i)%mod;
}

 

 

然后你还可以用线性逆元求阶乘逆元了

 

// 这里是一种用线性逆元解阶乘逆元的方法 
inline void get_finv2(){
    finv[0]=finv[1]=1;
    for(int i=2;i<=n;++i)
        finv[i]=finv[mod%i]*(mod-mod/i)%mod;
    for(int i=2;i<=n;++i)
        finv[i]=finv[i]*finv[i-1]%mod;
}

 

 
 

如果你看完这些不过瘾,给你几个网站用来生啃代码:
四法求逆元
逆元的几种求法

最后的最后,逆元的这些东西…随便学学就好,到时候用得到(也可能用不到)
于是Judge的课堂又这样水过去了一节…
欢迎下次光临! _(:з」∠)_

 

 

(求点赞,求推荐,求收藏! ღ( ´・ᴗ・` )比心 )

 

转载于:https://www.cnblogs.com/Judge/p/9383034.html

一、数据采集层:多源人脸数据获取 该层负责从不同设备 / 渠道采集人脸原始数据,为后续模型训练与识别提供基础样本,核心功能包括: 1. 多设备适配采集 实时摄像头采集: 调用计算机内置摄像头(或外接 USB 摄像头),通过OpenCV的VideoCapture接口实时捕获视频流,支持手动触发 “拍照”(按指定快捷键如Space)或自动定时采集(如每 2 秒采集 1 张),采集时自动框选人脸区域(通过Haar级联分类器初步定位),确保样本聚焦人脸。 支持采集参数配置:可设置采集分辨率(如 640×480、1280×720)、图像格式(JPG/PNG)、单用户采集数量(如默认采集 20 张,确保样本多样性),采集过程中实时显示 “已采集数量 / 目标数量”,避免样本不足。 本地图像 / 视频导入: 支持批量导入本地人脸图像文件(支持 JPG、PNG、BMP 格式),自动过滤非图像文件;导入视频文件(MP4、AVI 格式)时,可按 “固定帧间隔”(如每 10 帧提取 1 张图像)或 “手动选择帧” 提取人脸样本,适用于无实时摄像头场景。 数据集对接: 支持接入公开人脸数据集(如 LFW、ORL),通过预设脚本自动读取数据集目录结构(按 “用户 ID - 样本图像” 分类),快速构建训练样本库,无需手动采集,降低系统开发与测试成本。 2. 采集过程辅助功能 人脸有效性校验:采集时通过OpenCV的Haar级联分类器(或MTCNN轻量级模型)实时检测图像中是否包含人脸,若未检测到人脸(如遮挡、侧脸角度过大),则弹窗提示 “未识别到人脸,请调整姿态”,避免无效样本存入。 样本标签管理:采集时需为每个样本绑定 “用户标签”(如姓名、ID 号),支持手动输入标签或从 Excel 名单批量导入标签(按 “标签 - 采集数量” 对应),采集完成后自动按 “标签 - 序号” 命名文件(如 “张三
### 逆元的数概念与用法 #### 1. 模乘逆元的定义 在模运算中,如果存在一个整数 \(x\),使得 \(ax \mod m = 1\),那么 \(x\) 被称为 \(a\) 对于模数 \(m\) 的**模乘逆元**,通常记为 \(a^{-1} \mod m\)。这意味着当 \(a\) 和 \(x\) 相乘后取模 \(m\) 的结果为 1 时,\(x\) 是 \(a\)逆元[^1]。 #### 2. 存在条件 模乘逆元存在的必要条件是 \(a\) 和 \(m\) 必须互质(即 \(\gcd(a, m) = 1\))。这是因为只有当 \(a\) 和 \(m\) 互质时,才可能存在一个整数 \(x\) 满足上述等式。 #### 3. 求解方法 模乘逆元可以通过以下几种方法求解: - **扩展欧几里得算法**:这是最常用的求解方法之一。通过扩展欧几里得算法可以找到满足 \(ax + my = 1\) 的整数 \(x\) 和 \(y\),其中 \(x\) 即为 \(a\) 的模乘逆元。 - **费马小定理**:如果 \(m\) 是一个素数,并且 \(a\) 不是 \(m\) 的倍数,则 \(a^{m-2} \mod m\) 就是 \(a\) 的模乘逆元。 - **快速幂算法**:结合费马小定理,可以使用快速幂算法高效地计算模乘逆元。 以下是使用扩展欧几里得算法求解模乘逆元的代码示例: ```python def extended_gcd(a, b): if b == 0: return a, 1, 0 gcd, x1, y1 = extended_gcd(b, a % b) x = y1 y = x1 - (a // b) * y1 return gcd, x, y def mod_inverse(a, m): gcd, x, _ = extended_gcd(a, m) if gcd != 1: return None # 逆元不存在 else: return x % m ``` #### 4. 应用场景 模乘逆元在多个领域有广泛的应用: - **密码**:在 RSA 密算法中,模乘逆元用于生成公钥和私钥。 - **大数运算**:在需要对大数进行除法运算时,可以通过模乘逆元将除法转化为乘法,从而避免直接处理大数除法。 - **同余方程求解**:模乘逆元可以帮助解决形如 \(ax \equiv b \pmod{m}\) 的同余方程。 #### 5. 逆元与命题逻辑的关系 虽然逆元主要涉及模运算和数论,但在离散数中,命题逻辑也有类似的“逆”概念。例如,在命题公式中,如果一个公式 \(A\) 是重言式(永真式),则其否定形式 \(\neg A\) 是矛盾式(永假式)。这种逻辑上的“逆”关系与模乘逆元的概念有一定的类比性[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值