数论倒数又称逆元,在数论中倒数(逆元)是有特殊意义的,而且在数论中a的倒数不是1/a了,而是x,瞒足a*x = 1(mod p)而 x 并不一定是1/a.
(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转化为a*inv(b)就可以使用乘法的了。(其中inv(b)表示 b 关于 p 的逆元)
当然对逆元这一概念,只有当a 与 p 互质时才存在a关于p的逆元
a^(p-1) == 1 (mod p)
连边除以 a 得到 a ^ (p-2) = 1/a (mod p) 即
a ^ (p-2) = inv(a) (mod p)
然后用快速幂求一下就行了 复杂度为O(log n)
上代码好了
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);
}
a * x + b * y = 1
若a 与 b 互质, 则有解
而 x 就是 a 关于b 的逆元, 相应的 y 是 b 关于 a 的逆元;
证明就是,直接两边除以a 或 b 就行了
#include
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));
}
}