9乘法逆元
乘法逆元
定义
如果一个线性同余方程$ax\equiv 1\pmod b \(,则\)x\(称为\)a\mod b\(的逆元,记作\)a^{-1}$。
快速幂法
浅浅证明一下:
由定义可得\(ax \equiv 1 \pmod b\);
要根据费马小定理可得 \(a^{b-1}\equiv 1 \pmod b\)
联立可得 \(x \equiv a^{b-2}\pmod b\)
ll qpow(ll a, ll b, int mod)
{
ll ans = 1;
a = (a % mod + mod) % mod;
do
{
if (b & 1)
ans = (a * ans) % mod;
a = (a * a) % mod;
}while (b >>= 1);
return ans;
}
扩展欧几里得法
证明:
由扩展欧几里得可得:
\(ax+by=gcd(a,b)\)
若\(gcd(a,b)=1\),则\(ax+by=1\)
同时取模,可得\(ax\equiv 1 \pmod b\)。
void exgcd(int a, int b, int &x,int &y)
{
if(b == 0)
{
x = 1;
y = 0;
}
exgcd(b, a % b, y, x);
y -= a / b * x;
}
线性求逆元
求出1,2,......,n中每个数关于p的逆元。
如果对于每个数进行单次求解,以上两种方法就显得慢了,很有可能超时,所以下面讲一讲如何线性(\(O(n)\))求逆元。
对于\(\forall p \in Z\),由\(1 * 1 \equiv 1 \pmod p\)恒成立,故在\(p\)下1的逆元是1,而这是推算出其他情况的基础。
其次对于递归情况$ i^{-1}$,我们令
\(k = \lfloor \frac{p}{i} \rfloor,j = p \bmod i\),有 \(p = ki + j\)。再放到 \(\mod p\) 意义下就会得到:\(ki+j \equiv 0 \pmod p\);
两边同时乘 \(i^{-1} \times j^{-1}\):
\(kj^{-1}+i^{-1} \equiv 0 \pmod p\)
\(i^{-1} \equiv -kj^{-1} \pmod p\)
再带入$ j = p \bmod i$,有 \(p = ki + j\),有:
\(i^{-1} \equiv -\lfloor\frac{p}{i}\rfloor (p \bmod i)^{-1} \pmod p\)
我们注意到$ p \bmod i < i\(,而在迭代中我们完全可以假设我们已经知道了所有的模 p 下的逆元\) j^{-1}, j < i$。
故我们就可以推出逆元,利用递归的形式,而使用迭代实现:
inv[1] = 1;
for (int i=2; i<=n; i++)
{
inv[i] = (long long)(p - p / i) * inv[p % i] % p;
}
使用 \(p-\lfloor \dfrac{p}{i} \rfloor\) 来防止出现负数。
线性求任意n个数的逆元
如果需要求任意给定 n 个数\((1 \le a_i < p)\)的逆元,就需要下面的方法:
首先计算 n 个数的前缀积,记为$ s_i$,然后使用快速幂或扩展欧几里得法计算 \(s_n\) 的逆元,记为$ sv_n$。
因为$ sv_n$ 是 n 个数的积的逆元,所以当我们把它乘上 a_n 时,就会和 a_n 的逆元抵消,于是就得到了\(a_1\) 到 $a_{n-1} \(的积逆元,记为\) sv_{n-1}$。
同理我们可以依次计算出所有的 \(sv_i\),于是
$a_i^{-1} \(就可以用\) s_{i-1} \times sv_i $求得。
所以我们就在 $O(n + \log p) $的时间内计算出了 n 个数的逆元。
s[0] = 1;
for(int i=1; i <= n; i++)
{
s[i] = s[i-1] * a[i] % p;
}
sv[n] = qpow(s[n], p-2);
for(int i = n; i >= 1 ; i--)
{
sv[i - 1] = sv[i] * a[i] % p;
}
for(int i=1; i <= n; i++)
{
inv[i] = sv[i] * s[i-1] % p;
}

浙公网安备 33010602011771号