日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

乘法逆元笔记总结

發(fā)布時(shí)間:2024/1/1 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 乘法逆元笔记总结 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

乘法逆元

含義

首先,數(shù)學(xué)上的乘法逆元就是指直觀的倒數(shù),即 aaa 的逆元是 1a\displaystyle\frac{1}{a}a1? ,也即與 aaa 相乘得 111 的數(shù)。ax=1ax=1ax=1,則 xxxaaa 的乘法逆元。

如果到度娘上搜索逆元,會(huì)看到如下定義:(這里逆元素是逆元的全稱)

逆元素是指一個(gè)可以取消另一給定元素運(yùn)算的元素 。

這個(gè)定義似乎不太那么直觀……

我們來舉個(gè)例子吧,先再實(shí)數(shù)范圍舉例,由小學(xué)知識(shí)可知,如果一個(gè)代數(shù)式 FFF 乘一個(gè)數(shù) aaa 后,再乘它的倒數(shù) 1a\frac 1 aa1? ,相當(dāng)于沒有乘 aaa (這里不考慮 000 的情況),換句話說,我們乘 1a\frac 1 aa1? 后,取消了代數(shù)式 FFFaaa 后值增大的影響。

不難發(fā)現(xiàn)這符合逆元的定義,故我們可以說一個(gè)數(shù)和其倒數(shù)互為乘法逆元。

算法這里這里我們討論關(guān)于取模運(yùn)算的乘法逆元,即對(duì)于整數(shù) aaa ,與 aaa 互質(zhì)的數(shù) bbb 作為模數(shù),當(dāng)整數(shù) xxx 滿足 axmodb≡1ax\mod\,b≡1axmodb1 時(shí),稱 xxxaaa 關(guān)于模 bbb 的逆元,代碼表示是 a * x % b == 1 。

我們通常將 aaa 的逆元記作 a?1a^{-1}a?1

在算法競(jìng)賽中,經(jīng)常會(huì)遇到求解數(shù)據(jù)很大,則輸出模 109+710^9+7109+7 的解這類要求。加法、減法、乘法等操作,基于同余理論直接取模即可。但遇到除法時(shí),某步中間結(jié)果不一定能完成整除,就無法求解了。

舉個(gè)栗子
求3 * 6 / 3 對(duì)7 取模的結(jié)果。我們直接算出3 * 6 / 3的結(jié)果是6,對(duì)7取模得最終答案是6 。

但我們通常面對(duì)的問題是中間結(jié)果超過int甚至long long的范圍,而不得不在每一步基于同余理論取模,我們用這個(gè)例子嘗試一下:

還是求 3 * 6 / 3 % 7

第一步:3 * 6 == 18,18 % 7 == 4

第二步:4 這個(gè)中間結(jié)果再做 4 / 3 無法整除,就無法進(jìn)行下去了。

但我們可以求出除數(shù)3 關(guān)于模數(shù)7的逆元5(根據(jù)逆元定義,5 符合3 * 5 % 7 == 1),從而,用乘以5代替除以3。

上述第二步除法變乘法:4 * 5 == 20,20 % 7 == 6

從而也計(jì)算出了正確的結(jié)果6 。

故而我們需要一個(gè)算法求 除數(shù)取模逆元 ,從而在四則運(yùn)算取模的任務(wù)中,用逆元將除法轉(zhuǎn)為乘法。

求法

1.費(fèi)馬小定理

前置芝士:歐拉定理:若a,na,na,n互質(zhì),則a?(n)≡1(modn)a^{\phi(n)}\equiv 1 (\mod n)a?(n)1(modn)

費(fèi)馬小定理:當(dāng)有兩數(shù) aaa, ppp 滿足 gcd?(a,p)=1gcd ? ( a , p ) = 1gcd?(a,p)=1, 并且 ppp 是質(zhì)數(shù)時(shí),則有

ap?1≡1(modp)\begin{aligned} a^{p-1}\equiv 1\,\;(\mod p\;) \end{aligned}ap?11(modp)?

將該等式與 ax≡1(modp)ax\equiv 1(\mod p)ax1(modp) 對(duì)比可以驚奇地發(fā)現(xiàn):
x=ap?2\begin{aligned} x=a^{p-2} \end{aligned}x=ap?2?

逆元求出來之后,就可以用 快速冪 求出 ap?2a^{p-2}ap?2 的值了;

時(shí)間復(fù)雜度:大約 O(logp)O(log p)O(logp)

這里沒啥好貼的代碼了,貼一個(gè)快速冪吧:

//計(jì)算a^k%p int qmi(int a,int k,int p){int res=1;while(k){if(k&1) res=(LL)res*a%p;k>>=1;a=(LL)a*a%p;}return res; }

2.擴(kuò)展歐幾里得

前置芝士:裴蜀定理:對(duì)于任意的正整數(shù) a,ba,ba,b 一定存在正整數(shù) x,yx,yx,y 使得 ax+by=gcd(a,b);ax+by=gcd(a,b);ax+by=gcd(a,b); (并且也是能湊出來的最小正整數(shù))

由定義可知:ax≡1(modp)ax\equiv 1\,(\mod p)ax1(modp),這個(gè)式子等價(jià)于已知 a,pa,pa,p 求一個(gè)二元一次不定方程 ax=kp+1ax=kp+1ax=kp+1,移一下項(xiàng)得:ax?kp=1ax?kp=1ax?kp=1。這東西與 ax+by=gcd(a,b)ax+by=gcd(a,b)ax+by=gcd(a,b) 不是神似?就是擴(kuò)展歐幾里得算法。

附一小段擴(kuò)展歐幾里得代碼:

//返回gcd(a,b),計(jì)算x,y int exgcd(int a,int b,int &x,int &y){if(!b){x=1,y=0;return a;}int d=exgcd(b,a%b,y,x);y-=a/b*x;return d; }

相比于費(fèi)馬小定理,擴(kuò)展歐幾里得的使用限制更小,不再需要 ppp 是質(zhì)數(shù),只需要 a,pa,pa,p 互質(zhì)即可。

時(shí)間復(fù)雜度:大約 O(logn)O(logn)O(logn)

3.遞推計(jì)算階乘的逆元

當(dāng)我們要計(jì)算一大串連續(xù)的階乘的逆元時(shí),采用費(fèi)馬小定理或擴(kuò)展歐幾里得算法就有可能超時(shí),所以我們必須采用一個(gè)更快的算法。

fi=i!f_i=i!fi?=i! ,則可得:
inv(fi)≡inv(fi?1?(i))(modp)\begin{aligned} inv(f_{i})\equiv inv(f_{i-1}\cdot (i))(\mod p) \end{aligned}inv(fi?)inv(fi?1??(i))(modp)?

我們將右式乘開,則有:
inv(fi)≡inv(fi?1)?i?1(modp)\begin{aligned} inv(f_{i})\equiv inv(f_{i-1})\cdot i^{-1}(\mod p) \end{aligned}inv(fi?)inv(fi?1?)?i?1(modp)?

最后我們每一次只用處理i這一個(gè)數(shù)的逆元了。

下面是一小段預(yù)處理代碼(提前打表):

//fact[i]表示i的階乘,infact[i]表示i的階乘的逆元。 fact[0]=infact[0]=1;for(int i = 1;i < N;i ++ ){fact[i]=(LL)fact[i - 1]*i%mod;infact[i]=(LL)infact[i - 1]*qmi(i,mod - 2,mod)%mod;}

4.遞推計(jì)算連續(xù)的數(shù)的逆元 (線性求逆)

當(dāng)我們要計(jì)算連續(xù)的數(shù)的逆元時(shí),我們可以采用以下遞推式:
inv(i)=(p??pi?)×inv(pmodi)modp\begin{aligned} inv(i)=(p-\lfloor\frac{p}{i}\rfloor)\times inv(p\mod i)\mod p \end{aligned}inv(i)=(p??ip??)×inv(pmodi)modp?

證明:設(shè) t=?pi?,k=pmodit=\lfloor\frac{p}{i}\rfloor,k=p\mod it=?ip??,k=pmodi ,那么顯然有
t×i+k≡0(modp)\begin{aligned}t\times i+k\equiv 0(\mod p)\end{aligned}t×i+k0(modp)?

變形可得
?t×i≡k(modp)\begin{aligned} -t\times i\equiv k(\mod p) \end{aligned}?t×ik(modp)?

兩邊同時(shí)除以 ikikik 得到
?t×1k≡1i(modp)\begin{aligned} -t\times\frac{1}{k}\equiv\frac{1}{i}(\mod p) \end{aligned}?t×k1?i1?(modp)?

inv(i)≡?t×inv(k)(modp)\begin{aligned} inv(i)\equiv-t\times inv(k)(\mod p) \end{aligned}inv(i)?t×inv(k)(modp)?

所以有
inv(i)=(p??pi?)×inv(pmodi)modp\begin{aligned} inv(i)=(p-\lfloor\frac{p}{i}\rfloor)\times inv(p\mod i)\mod p \end{aligned}inv(i)=(p??ip??)×inv(pmodi)modp?

參考代碼:

#include <cstdio> #include <cstring> #include <iostream> #include <algorithm>using namespace std;const int maxn = 3e6 + 10; long long infact[maxn], n, p;int main() {scanf("%lld%lld", &n, &p);infact[0] = 0, infact[1] = 1;//初始化1的逆元為1printf("%lld\n", infact[1]);for (int i = 2; i <= n; ++i){infact[i] = (p - p / i) * infact[p % i] % p;//上文中的式子printf("%lld\n", infact[i]);}return 0; }

總結(jié)

以上是生活随笔為你收集整理的乘法逆元笔记总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。