逆元模版大全
扩展欧几里得求逆元
1、时间复杂度:\(O(logn)\)
2、推理:
-
\(ax \equiv g \ (mod \ p)\),所以可以转化为:\(ax+py=g\) 。
-
又因为由 \(exgcd\) 求出来的 \(d\) 为 \(gcd(a,b)\),所以得满足 \(d \ | \ g\) ,才能有解。
-
这里令 \(g=1\),则 \(x\) 为我们所求的 \(a\) 的逆元 \(a^{-1}\),所以我们需要满足 \(gcd(a,p)=1\),才能求出 \(a\) 的逆元 \(a^{-1}\),否则无解。
template<typename T>
struct Inv{
inline void exgcd(T a, T &x, T &y, T p = 1e9 + 7) {
if (!p) {
x = 1;
y = 0;
return;
}
exgcd(p, y, x, a % p);
y -= a / p * x;
}
inline T get_inv(T a, T p = 1e9 + 7) {// 逆元x,需要满足__gcd(a, p)==1
T x, y;
exgcd(a, x, y, p);
x = (x % p + p) % p;
return x;
}
};
Inv<i64> t;
快速幂 + 费马小定理求逆元:时间复杂度为:\(O(logn)\)
- 由于 \(gcd(a,p)=1\),则由费马小定理得:\(a^{p-1} \equiv 1 \ (mod \ p)\),又 \(ax \equiv 1 \ (mod \ p)\),则 \(x \equiv a^{-1}a^{p-1} \ (mod \ p) \Rightarrow x \equiv a^{p-2} \ (mod \ p)\)。
template<typename T>
struct Inv{
inline T qp(T a, T b, T p = 1e9 + 7) {
a %= p;
T res = 1;
while (b) {
if (b & 1) res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
inline T get_inv(T a, T p = 1e9 + 7) {
return qp(a, p - 2, p);
}
};
Inv<i64> t;
线性预处理 \(1-1e7\) 以内单个数的逆元,整体时间复杂度为:\(O(n)\)
-
具体推导过程:我们令 \(f(i)=i^{-1} \ mod \ p\) 表示 \(i\) 的逆元,令 $k=\left \lfloor \frac{p}{i} \right \rfloor $,然后有 \(p=ki+j\),其中 \(j=p \ mod \ i\),然后我们可以得到:\(ki+j \equiv 0 \ (mod \ p)\) ,我们让两边同时乘上 \(i^{-1}j^{-1}\),可以得到 \(i^{-1} \equiv -kj^{-1} \ (mod \ p)\),然后我们将前面的式子带入这个式子中,可以得到:\(i^{-1} \equiv (-\left \lfloor \frac{p}{i} \right \rfloor \ (p \ mod \ i)^{-1}) \ (mod \ p)\) 。
-
模版:洛谷P3811。
template<typename T>
struct Inv{
int n;
vector<T> inv;
Inv() {}
Inv(int n_, T p = 1e9 + 7) : inv(n_ + 1) {
n = n_;
inv[1] = 1LL;
for (T i = 2; i <= n; i++) inv[i] = (p - p / i) * inv[p % i] % p;
// 如果inv[i]=0,表示i在模p意义下没有逆元
}
inline T get_inv(T a) {
return inv[a];
}
};
Inv<i64> t;
递归求单个数的逆元,时间复杂度:\(O(n^{\frac{1}{3}})\)
template<typename T>
struct Inv{
inline T get_inv(T n, T p = 1e9 + 7) {
if (n == 1) return (T)1;
return (p - p / n) * get_inv(p % n, p) % p;
}
};
Inv<i64> t;
线性求任意给定的 \(n\) 个数的逆元,时间复杂度:\(O(n)\)
- 模版:洛谷P5431。
template<typename T>
struct Inv{
inline T qp(T a, T b, T p = 1e9 + 7) {
a %= p;
T res = 1;
while (b) {
if (b & 1) res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
inline T get_inv(T a, T p = 1e9 + 7) {
return qp(a, p - 2, p);
}
int N;
vector<T> a;
vector<T> fac;
vector<T> inv;
Inv(int N_, vector<T> &a_, T p = 1e9 + 7) : fac(N_ + 1), inv(N_ + 1) {
a = a_;
N = N_;
fac[0] = 1;
for (T i = 1; i <= N; i++) fac[i] = fac[i - 1] * a[i] % p;
T ans = get_inv(fac[N], p);
for (T i = N; i >= 1; i--) {
inv[i] = ans * fac[i - 1] % p;
ans = ans * a[i] % p;
}
}
};

浙公网安备 33010602011771号