求逆元問題是數論中一類比較基礎的題目,它常常會與組合數,質數等聯系起來。今天我們就來總結一下求逆元的方法,根據數據范圍不同有三種,接下來就一一介紹。
-------------------------------------------------------------------------------
方法1.通過擴展歐幾里得算法求逆元
這個算法很常見,在這里就不再累述,直接給出代碼。
- 求解ax+by=gcd(a,b),亦即ax≡1(mod b)。函數返回值是a,b的最大公約數,而x即a的逆元。
- 注意a, b不能寫反了。
- gcd(a, b) > 1時逆不存在

1 int ex_gcd(int a, int b, int &x, int &y) { 2 int ret, tmp; 3 if (b == 0) { 4 x = 1; 5 y = 0; 6 return a; 7 } 8 ret = ex_gcd(b, a % b, x, y); 9 tmp = x; 10 x = y; 11 y = tmp - a / b * y; 12 return ret; 13 }
方法2.通過快速冪求逆元
由於費馬小定理,a^(p-1)=1(mod p)-->1/a=a^(p-2)(mod p),故a的逆元為a^p-2.注意這個方法要求模的數必須為質數,傳入a和mod-2即可得到結果。

LL quick_inverse(LL n, LL p) { LL ret = 1,exponent = p; for (LL i = exponent; i; i >>= 1, n = n * n % mod) { if (i & 1) { ret = ret * n % mod; } } return ret; }
方法3.通過遞推求1~n的逆元
我們可以通過inv[i]=inv[p%i]*(p-p/i)%p遞推得到逆元。適用於n比較小的情況

1 int inv[N]; 2 void get_inverse(int n, int p) { 3 inv[1] = 1; 4 for (int i = 2; i <= n; ++i) { 5 inv[i] = (p - p / i) * inv[p % i] % p; 6 } 7 }
特殊情況.通過遞推求n!
我們可以利用invf[i]=invf[i+1]*(i+1)%p這個公式反遞推得到1!~n!的逆元。

1 int invf[N], factor[N]; 2 void get_factorial_inverse(int n, int p) { 3 factor[0] = 1; 4 for (int i = 1; i <= n; ++i) { 5 factor[i] = i * factor[i - 1] % p; 6 } 7 invf[n] = quick_inverse(factor[n], p); 8 for (int i = n-1; i >= 0; --i) { 9 invf[i] = invf[i + 1] * (i + 1) % p; 10 } 11 }
----------------------------------------------------------------------------------
本來想再寫一篇組合數的,但肯定沒有苟神講得好,所以直接附上鏈接:組合數取模
感覺講得不好,畢竟蒟蒻還不是很能理解里面的內涵,只是總結一下,等用到就不會很無措,大家多多包涵啦。
-END-