乘法逆元3种方法总结[最全]
建議大家可以先去看看這篇博文
(https://www.cnblogs.com/dupengcheng/p/5487362.html)
乘法逆元:ax≡1 (mod p) 這個等式用中文描述就是 a乘一個數x并模p等于1,即 a%p*x%p=res【并非指res等于1】,而是res%p=1;其中的x為滿足范圍還要對p求模
需知道的是:
若ax≡1 mod f, 則稱a關于1模f的乘法逆元為x。也可表示為ax≡1(mod f)。
當a與f互素時,a關于模f的乘法逆元有解。如果不互素,則無解。如果f為素數,則從1到f-1的任意數都與f互素,即在1到f-1之間都恰好有一個關于模f的乘法逆元?!景俣劝倏?乘法逆元】
什么是逆元,為什么要求逆元?
計蒜客某題所表述:
那么了解基本知識后,我們來求逆元:
求逆元分為兩類:
1.a p 不互質時逆元無解
可用公式實現相同功能:
證明:
推薦題目:藍橋杯小數第n位
2.a p 互質時:
逆元的求法主要有三種(按快慢排序):
第一:線性打表遞推法(遞推公式inv[i]=(p-p/i) * inv[p%i]%p)。
第二:擴展歐幾里得算法。(詳解)
第三:費馬小定理(快速冪qpow(a,p-2,p))。-(最容易理解)
下面我們把每種求法的模板呈上:
例題引入:乘法逆元
Description
這是一道模板題。
給定正整數 n 與 p ,求 1~n 中的所有數在模 p 意義下的乘法逆元。
Input
一行兩個正整數 n 與 p
1 ≤ n ≤ 3×106 , n < p < 20000528
p 為質數。
Output
n 行,第 i 行一個正整數,表示 i 在模 p 意義下的乘法逆元。
Sample Input
Sample Output
1 7 9 10 8 11 2 5 3 4第一:線性打表遞推法(遞推公式inv[i]=(p-p/i)inv[p%i]%p)
時間對比:
參考于:(https://blog.csdn.net/xuechen_gemgirl/article/details/80332859)
第二:擴展歐幾里得算法
時間復雜度:
為什么可以用擴展歐幾里得求得逆元?
我們都知道模就是余數,比如12%5=12-5 * 2=2,18%4=18-4*4=2。(/是程序運算中的除)可知a%b=a-(a/b)b
那么ax≡1 (mod p)即ax-yp=1.把y寫成+的形式就是ax+py=1,為方便理解下面我們把p寫成b就是ax+by=1。就表示x是a的模b乘法逆元,y是b的模a乘法逆元。然后就可以用擴展歐幾里得求了。
摘自上面鏈接(https://www.cnblogs.com/dupengcheng/p/5487362.html,推薦大家先看一遍)
很多人,包括我一直無法理解擴展歐幾里得算法,在我看了好多博文后才大概了解。就拿我碰到的來說:
一擴展歐幾里得可以求最大公約數。
二求ax+by=gcd(a,b)的解x,y。逆元就包括其中。
x是a的模b乘法逆元,y是b的模a乘法逆元(即gcd()=1時的x/y)
現在來講一下擴展歐幾里得到底怎么來的:
其實我覺得大家只要搞懂后面遞歸的x,y怎么求就幾乎沒問題的了。
原式:ax+by=gcd(a,b)
遞歸:bx+(a%b)y^=gcd(a,b) 【x^和 y^就是上一步的x,y】
其中:a%b=a-(a/b)b
帶入后:ay^+b ( x ^ - ( a/b ) y ^ )=gcd(a,b);
再與原式對比:ax+by=gcd(a,b)
得出:{
x=y^;
x^-(a/b ) y ^=y;
}
這就是遞歸過程中,x和y的由來
而當b=0時,有:(遞歸結束時){a=gcd(a,b),x=1,y=0}
a1+b0=a=gcd(a,b)
可得出一個特解a(最大公約數)
這樣就可以得到每兩個相鄰狀態的x和y的轉化了,就可以在求gcd(a,b)的同時求對x,y求解
相信對于擴展歐幾里得算法,大家會有疑問為什么b=0時x=1;y=0?
其實當達到遞歸基時,此時的a就是gcd(最大公約數),b=0,那么有ax+by=a。
故x必須等于1,y可以取任何正整數。
我還是有疑問上面說了“x是a的模b乘法逆元,y是b的模a乘法逆元”
大家都統一b=0時x=1;y=0;。既然y可以取任何正整數那么我就要換一個當b=0時:x=1;y=1;這個“x是a的模b乘法逆元,y是b的模a乘法逆元”結論還是成立的。
還有一點就是建議y取0,如果取其他數組,由于y增長較快,可能會有越界的問題。
#include<bits/stdc++.h> using namespace std; int exgcd(int a,int b,int &x,int &y)//擴展歐幾里得算法 {if(b==0){x=1;y=0;return a; //到達遞歸邊界開始向上一層返回}int r=exgcd(b,a%b,x,y);int temp=y; //把x y變成上一層的y=x-(a/b)*y;x=temp;return r; //得到a b的最大公因數 } //事實證明還是遞推快 遞推快但是耗空間 int main(void) {int a,p;//p是mod數int x,y;while(~scanf("%d %d",&a,&p)){for(int i=1;i<=a;i++){exgcd(i,p,x,y);if(x>0)printf("%d\n",x);elseprintf("%d\n",x+p);//確保逆元x為正整數}}return 0; }第三:費馬小定理(快速冪qpow(a,p-2,p))
時間復雜度對比:
為什么可以用費馬小定理來求逆元呢?
(前提是a p 互質)
由費馬小定理 ap-1≡1(mod p) , 變形得 a * ap-2≡1(mod p),答案已經很明顯了:若a,p互質,因為a * ap-2≡1(mod p)且a*x≡1(mod p),則逆元x=ap-2(mod p),用快速冪可快速求之。
摘自上面鏈接(https://www.cnblogs.com/dupengcheng/p/5487362.html)
明顯在大量數據的時候遞推打表快,平時普通問題用另外兩個比較方便,但是由于本人數學知識薄弱不能給出證明【捂臉】
給個大佬講解的鏈接:https://blog.csdn.net/guhaiteng/article/details/52123385
總結
以上是生活随笔為你收集整理的乘法逆元3种方法总结[最全]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 测试Python是否安装成功—pytho
- 下一篇: sql分组查询group by结合cou