乘法逆元
乘法逆元
定义
对于一个线性同余方程 \(ax \equiv 1 \pmod b\),则 \(x\) 称为 \(a \bmod b\) 的逆元,记作 \(a^{-1}\)。
\(a \bmod b\) 的逆元存在当且仅当 \(a\perp p\)
费马小定理求逆元
对于\(p\)为质数,由费马小定理
\[a^{p-1}\equiv 1\pmod b
\]
得
\[\begin{align*}
ax &\equiv a^{b-1} \pmod b\\
x &\equiv a^{b-2} \pmod b
\end{align*}
\]
于是可以用快速幂求解
il int qpow(int a,int b,int p){
ri int as=1;
while(b>0){
if(b&1) as=as*a%p;
a=a*a%p,b>>=1;
}
return as;
}
il int Inv(int a,int p){
return qpow(a,p-2,p);
}
扩展欧几里得法求逆元
递归解线性同余方程 \(ax \equiv 1 \pmod b\)即可
il void exgcd(cs int a,cs int b,int &x,int &y,int &g){
if(!b) return x=1,y=0,g=a,void();
return exgcd(b,a%b,y,x,g),y-=x*(a/b),void();
}
il int Inv(int a,int p){
int x=0,y=0,g=0;
exgcd(a,p,x,y,g);
return (x%p+p)%p;
}
线性求1~n的逆元
\[x^{-1}\equiv
\begin{cases}
1, x=1
\\
- \lfloor \frac{p}{x} \rfloor \cdot (p\bmod x)^{-1} ,otherwise
\end{cases}
\pmod p
\]
il void solve(int n,int p){
inv[1]=1;
for(ri int i=2;i<=n;++i){
inv[i]=(-p/i*inv[p%i]%p+p)%p;
}
return;
}
线性求任意n个数的逆元
首先计算 \(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\) 个数的逆元。
il void solve(int n,int p){
s[0]=1;
for(ri int i=1;i<=n;++i){
s[i]=s[i-1]*a[i]%p;
}
sv[n]=Inv(s[i],p);
for(ri int i=n;i;--i){
sv[i-1]=sv[i]*a[i]%p;
}
for(ri int i=1;i<=n;++i){
inv[i]=s[i-1]*sv[i]%p;
}
return;
}
I went to the woods because I wanted to live deliberately, I wanted to live deep and suck out all the marrow of life, and not when I had come to die, discover that I had not live.