在分数取模时总会用到逆元运算
在模运算中
(a + b) % p = (a%p + b%p) %p (对) (a - b) % p = (a%p - b%p) %p (对) (a * b) % p = (a%p * b%p) %p (对) (a / b) % p = (a%p / b%p) %p (错)
对于除法的模运算不适合,所以需要定义一个新的东西来求除法模运算,这个东西就是逆元
定义:
(a/b)(mod p)=(ainv[b])(mod p)或者
ab≡1(mod P)`
inv[b]就是b的逆元 a就是b的逆元,或者ab或为逆元
则根据定义可知
除以一个数再取模等同于乘以这个数的逆元再取模
但是我们不能直接说一个数的逆元是多少,
应该这么说: 一个数 x 在模 p 的条件下的逆元是多少
比如2 * 3 % 5 = 1,那么3就是2关于5的逆元,或者说2和3关于5互为逆元
(a*inv[b])%p,inv[b]就是a关于p的逆元
条件:a与p互为质数,a才有关于p的逆元
转换除法模运算
根据取模运算
(a + b) % p = (a%p + b%p) %p (对) (a - b) % p = (a%p - b%p) %p (对) (a * b) % p = (a%p * b%p) %p (对) (a / b) % p = (a%p / b%p) %p (错)
(a / b) % p = (a * inv(b) ) % p = (a % p * inv(b) % p) % p
## 求逆元
### 方法1--费马小定理:
如果p是一个质数,而整数a不是p的倍数,则有a^(p-1)≡1(mod p)。 a^(p-1) ≡1 (mod p) 两边同除以a a^(p-2) ≡1/a (mod p) a^(p-2) ≡ inv(a) (mod p) inv(a) = a^(p-2) 即可求出a的逆元时a^(p-2)
用快速幂求,复杂度O(logn)
LL pow_mod(LL a, LL b, LL p){//a的b次方求余p LL ret = 1; while(b){ if(b & 1) ret = (ret * a) % p; a = (a * a) % p; b >>= 1; } return ret; } LL Fermat(LL a, LL p){//费马求a关于b的逆元 return pow_mod(a, p-2, p); }
方法2--扩展欧几里得
ax + by = 1
如果ab互质,有解
这个解的x就是a关于b的逆元
y就是b关于a的逆元
两边同时求余b
ax % b + by % b = 1 % b
ax % b = 1 % b
ax = 1 (mod b)
反之可证明y
用扩展欧几里得模板求
#include<cstdio> typedef long long LL; void ex_gcd(LL a,LL b,LL &x,LL &y,LL &d){ if(!b){ d=a,x=1,y=0; }else{ ex_gcd(b,a%b,y,x,d); y-=x*(a/b); } } LL inv(LL t, LL p){//如果不存在,返回-1 LL d, x, y; ex_gcd(t, p, x, y, d); return d==1 ? (x%p+p)%p : -1; } int main(){ LL a, p; while(~scanf("%lld%lld", &a, &p)){ printf("%lld\n", inv(a, p)); } }
例题:
hdu1576
求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。
因为9973为质数,作为p
本题要求b的逆元,设c为b的逆元
(A/B)mod P = (A/B)1mod p = (A/B)BC mod p=AC(mod p);
利用费马小定理得到C=B^(p-2)
答案就是(AC)%p=(A%pC%p)%p
所以先利用费马小定理得到逆元,利用快速幂
再代入等式求出答案