求除法取模(a/b)%c要用到逆元即 (a/b)%c=a*(b关于模c的逆)%c
逆元类似于实数运算中的倒数,因为乘法是可以直接取模的,所以我们可以将除法转换成乘法,用a乘b的倒数即a乘b的逆元然后去取模就可以了。
逆元怎么求呢?
(a和p互质,a才有关于p的逆元)
1:根据费马小定理,我们可得出当p是素数时,对任意x,都有x^(p)≡ x(modp),
若x无法被p整除,那么x^(p-1)≡ 1(modp),
那么可得出当模数p为素数x^(p-2)就是x的逆元。
const int mod = 1000000009;
long long quickpow(long long a, long long b) {
if (b < 0) return 0;
long long ret = 1;
a %= mod;
while(b) {
if (b & 1) ret = (ret * a) % mod;
b >>= 1;
a = (a * a) % mod;
}
return ret;
}
long long inv(long long a) {
return quickpow(a, mod - 2);
}
2:扩展欧几里德算法
a*x + b*y = 1
如果ab互质,有解。
那么两边同时modp
ax%p≡1%p那么ax≡1(modp)
x就是a关于b的逆元
#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));
}
}
3:逆元线性筛法
用来求1,2,3....n关于p的逆元,复杂度O(n)
const int mod = 1000000009;
const int maxn = 10005;
int inv[maxn];
inv[1] = 1;
for(int i = 2; i < 10000; i++)
inv[i] = inv[mod % i] * (mod - mod / i) % mod;
(忘了说, a和p互质,a才有关于p的逆元)