乘法逆元小结
在求解除法取模問(wèn)題(a/b)%m時(shí),我們可以轉(zhuǎn)化為(a%(b?m))/b,
但是如果b很大,則會(huì)出現(xiàn)爆精度問(wèn)題,所以我們避免使用除法直接計(jì)算。
可以使用逆元將除法轉(zhuǎn)換為乘法:
假設(shè)b存在乘法逆元,即與m互質(zhì)(充要條件)。設(shè)c是b的逆元,即b?c≡1(modm),那么有a/b=(a/b)?1=(a/b)?b?c=a?c(modm)
即,除以一個(gè)數(shù)取模等于乘以這個(gè)數(shù)的逆元取模。
擴(kuò)展歐幾里得算法:
要求a,m互素。存在唯一解。
之前總結(jié)過(guò)擴(kuò)展歐幾里得算法
代碼:
int extgcd(int a, int b, int& x, int& y) {int d = a;if(b != 0){d = extgcd(b, a % b, y, x);y -= (a / b) * x;}else {x = 1;y = 0;}return d; } int mod_inverse(int a, int m) {int x, y;extgcd(a, m, x, y);return (m + x % m) % m; }費(fèi)馬小定理:
在p是素?cái)?shù)的情況下,對(duì)任意整數(shù)x都有xp≡x(mod)p。
如果x無(wú)法被p整除,則有xp?1≡1(modp)。
可以在p為素?cái)?shù)的情況下求出一個(gè)數(shù)的逆元,x?xp?2≡1(modp),xp?2即為逆元。
代碼:
利用快速冪求出逆元。歐拉函數(shù):
令?(m)表示小于等于m且與m互素的正整數(shù)的個(gè)數(shù)。
如果x和m互質(zhì),則有x?(m)≡1(modm),即x×x?(m)?1≡1(modm),x?(m)?1即為x的逆元。
在m為質(zhì)數(shù)的情況下,?(m)=m?1,即為費(fèi)馬小定理。
代碼:
關(guān)鍵是求出歐拉函數(shù)的值。
利用歐拉函數(shù)的積性性質(zhì):
對(duì)于任意整數(shù)n,可以將它分解n=pk11?pk22?pk33...pkmm,其中pi為質(zhì)數(shù)。
其中?(n)=?(p1k1)??(pk22)...?(pkmm)
最后轉(zhuǎn)化為?(n)=n?∏(pi?1)/pi
對(duì)給定n進(jìn)行整數(shù)分解。時(shí)間復(fù)雜度O(n??√)。
int eurler_phi(int n) {int res = n;for(int i = 2; i * i <= n; i++){if(n % i == 0){res = res / i * (i - 1);while(n % i == 0) n /= i;}}if(n != 1) res = res / n * (n - 1);return res; }篩法求歐拉函數(shù)值的表,利用埃氏篩法,每次發(fā)現(xiàn)質(zhì)因子就把他的倍數(shù)的歐拉函數(shù)乘上(p?1)?p。時(shí)間復(fù)雜度O(maxn)。
如ACdreamers博客里介紹,利用定理進(jìn)行優(yōu)化:
當(dāng)n為奇數(shù)時(shí),有?(2n)=?(n)
因?yàn)?n是偶數(shù),偶數(shù)與偶數(shù)一定不互素,所以只考慮2n與小于它的奇數(shù)互素的情況,則恰好就等于n的歐拉函數(shù)值。
int euler[maxn]; void euler_phi2() {for(int i = 1; i < maxn; i++){if(i % 2 == 0) euler[i] = i / 2;else euler[i] = i;}for(int i = 3; i < maxn; i += 2){if(euler[i] == i){for(int j = i; j < maxn; j += i){euler[j] = euler[j] / i * (i - 1);}}} }線性時(shí)間求所有逆元:
規(guī)定p為質(zhì)數(shù),且1?1≡1(modp)
設(shè)p=k?a+b,b<a,1<a<p,即k?a+b≡0(modp)
兩邊同時(shí)乘以a?1?b?1,得到
k?b?1+a?1≡0(modp)
a?1≡?k?b?1(modp)
a?1≡?p/a?(pmoda)?1(modp)
從頭開(kāi)始掃一遍即可,時(shí)間復(fù)雜度O(n)
代碼:
int inv[maxn]; inv[1] = 1; for(int i = 2; i < maxn; i++)inv[i] = (p - p / i) % p * inv[p % i];轉(zhuǎn)載于:https://www.cnblogs.com/Tuesdayzz/p/5758670.html
總結(jié)
- 上一篇: pppcloud云主机内LINUX用户安
- 下一篇: Openstack的RPC通信代码调用架