乘法逆元
若整数(b,p)互质,并且(b|a),则存在一个整数(x)使得(a/b≡a*x(mod p)) ,则称(x)为(b) mod (p)的乘法逆元
记为(b-1)(mod (p))
我们先来看看有什么用
当输出结果很大时,要模一个mod再输出
((a+b)\%mod=a\%mod+b\%mod)
((a-b)\%mod=a\%mod-b\%mod)
((a*b)\%mod=a\%mod*b\%mod)
((a/b)\%mod)
乘法逆元派上用场了,设(b)模(p)的乘法逆元为(inv)
((a/b)\%p=(a*inv)\%p=a\%p*inv\%p)
为什么呢? 因为(b*inv≡1(mod p))
(a/b*b*inv=a*inv≡ a/b(mod p))
举个例子 要求(110/10)%7
(11x≡1 (mod 7) x=9)
((110/10)\%7=(110\%7)*(9\%7)=5*2\%7=3)
接下来是三种代码实现
1扩展欧几里得(exgcd) O(nlogn)
(ax!≡1)(mod (p)) 设(ax=yp+1,b=-p) 则(ax+by=1)
void exgcd(int a,int b)
{
if(b==0) g=a,x=1,y=0;
else{
exgcd(b,a%b);
int x1=y,y1=x-a/b*y;
x=x1,y=y1;
printf("%d*(%d)+%d*(%d)=%d
",a,x,b,y,g);
}
}
inv[a]=(x+p)%p;
2费马小定理O(nlogn)
复杂度 欧拉函数(O(n)),快速幂(O(logn))
假如(p)是质数,且(gcd(a,p)=1),那么 (a^{p-1}≡1)(mod (p))
由费马小定理 (a^{p-1} ≡1)$ , 变形得$$aa^{p-2}≡1((mod p),答案已经很明显了:若)a,p(互质,因为且)aa^{p-2}≡1$$(mod p)且a*x≡1(mod p)(,则)x=a^{p-2}$,用快速幂可快速求之.
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=3e6+5;
inline int read() {
int x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x;
}
typedef long long LL;
int n,p;
inline LL qpow(LL a,LL b) {
LL ans=1;
while(b) {
if(b&1) ans=ans*a%p;
a=a*a%p;
b>>=1;
}
return ans;
}
int main() {
n=read();p=read();
for(int i=1;i<=n;+i++)
printf("%d
",qpow(i,p-2));
return 0;
}
3欧拉定理O(nlogn)
定理内容:如果(a,p)互质,那么(a^φ(p) ≡ 1),当 p 为质数时,(φ(p)=p-1)。
同理,结合同余方程,得 (x=a^{p-2})(mod p),用快速幂可快速求之即可
代码同上
4线性递推 O(n)
#include<bits/stdc++.h>
using namespace std;
#define N 3000010
typedef long long ll;
int n,p;
ll inv[N];
int main(){
scanf("%d%d",&n,&p);
puts("1");
inv[1]=1;
for(int i=2;i<=n;i++) {
inv[i]=(ll)p-(p/i)*inv[p%i]%p;
printf("%lld
",inv[i]);
}
return 0;
}
lg T118233 一本通(蓝)P400