乘法逆元
也挺简单
定义:
若 \(a,m\) 互质,且满足:
\[a\times x\equiv 1 \pmod{m}
\]
则称 \(x\) 是 \(a\) 在 \(\bmod b\) 意义下的乘法逆元,也记为 \(a^{-1}\)。
用途:
主要用于 \(\frac{x}{y} \bmod m\) 求值,一般是因为无法化简(例如数太大。
求法:
1. \(exgcd\):
\[ax\equiv 1 \pmod{m}
\]
转化得:
\[ax+my=1
\]
运用 \(exgcd\) 求解即可。
CODE(点击查看)
void exgcd(int a,int b,int &x,int &y){
if(b==0) x=1,y=0;
else exgcd(b,a%b,y,x),y-=a/b*x;
}
int main(){
int a,m; scanf("%d%d",&a,&m);
int x,y;
exgcd(a,m,x,y);
printf("%d",(x%m+m)%m); //注意x的取值范围。
}
2.费马小定理(m是质数):
我们将费马小定理带入原式,得:
\[ax\equiv a^{m-1} \pmod{m}
\]
\[x\equiv a^{m-1} \div a \pmod{m}
\]
\[x \equiv a^{m-2} \pmod{m}
\]
所以我们只需求 \(a^{m-2}\) 即可,用快速幂。
COED(点击查看)
inline int fpow(int a,int b,int mod){
int ans=1;
while(b){
if(b&1) ans=a*ans%mod;
a=a*a%mod;
b>>=1;
}
return ans%mod;
}
int main(){
int a,m; scanf("%d%d",&a,&m);
printf("%d",fpow(a,m-2,m));
}
3.线性求法(求得 \(1 \text{ ~ } n\) ):
这种方法在但求一个时慢于前两种,但求 \(1 \text{ 到 } n\) 是优于前两种例题。
设 \(m=k \times a+r (1 \le r < a < m)\)
于是有:
\[ka+r \equiv 0 \pmod{m}
\]
乘上 \(r^{-1},a^{-1}\) ,得:
\[kr^{-1}+a^{-1}\equiv 0 \pmod{m}
\]
\[a^{-1}\equiv -kr^{-1} \pmod{m}
\]
\[a^{-1}\equiv -\left\lfloor\dfrac{m}{a}\right\rfloor\times(m \bmod a)^{-1} \pmod{m}
\]
我们又知道,\(1^{-1}\) 为 \(1\) 于是就可以线性推了。
CODE(例题,点击查看)
#include<bits/stdc++.h>
using namespace std;
const int N=3e6+5;
long long n,p,inv[N];
template<typename T>
inline void read(T &x){
char s=getchar();x=0;bool pd=false;
while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();}
while('0'<=s&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();
if(pd) x=-x;
}
int main(){
read(n),read(p);
inv[1]=1;
for(int i=2;i<=n;i++)
inv[i]=(p-p/i)*inv[p%i]%p;
for(int i=1;i<=n;i++)
printf("%lld\n",inv[i]);
}
CODE(主要代码,点击查看)
inv[1]=1;
for(int i=2;i<=n;i++)
inv[i]=(p-p/i)*inv[p%i]%p;
4.阶乘求逆元:
求:\(1! \text{ 到 } n!\) 的逆元。
给出一个式子,其中 \(v(i)\) 表示 \(i\) 的逆元。
\[v((i-1)!)=\frac{1}{(i-1)!}=\frac{1}{i!}*i=v(i!)*i
\]
于是乎又可以线性推了。
然而这种做法还可以求 \(l \text{ 到 } r\) 的逆元。
具体的:
\[v(i)=\frac{1}{i}=\frac{1}{i!}\times(i-1)!=v(i!)\times(i-1)!
\]
然后可求。
附:有趣的题:
给定一个长度为 \(n\) 的序列 \(a\) ,求 \(a_1 \text{ 到 } a_n\) 所有数的乘法逆元。
\(1 \le n \le 5e6\) (要求复杂度 \(\operatorname{O} n\))
做法:
先维护前缀积 \(q_i\)
通过:
\[q_i^{-1}\times a_i=\frac{1}{\prod\limits_{j=1}^ia_j}\times a_i=q_{i-1}^{-1}
\]
推得 \(q^{-1}\) 的值。
然后通过:
\[q_i^{-1}\times q_{i-1}=\frac{1}{\prod\limits_{j=1}^ia_j}\times\prod\limits_{j=1}^{i-1}a_j=a_i^{-1}
\]
得解。
——————————————————————————————————————————————————————————————————————————————————————————————————————————
本文来自博客园,作者:xrlong,转载请注明原文链接:https://www.cnblogs.com/xrlong/articles/17072952.html