乘法逆元

乘法逆元

若整数(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

原文地址:https://www.cnblogs.com/ke-xin/p/13692148.html