乘法逆元

首先,我想说——学会了乘法逆元,就相当于打开了模世界的大门!

定义

  若在mod p意义下,对于一个整数a,有a*b≡1(mod p),那么这个整数d即为a的 乘法逆元,同时a也为d的乘法逆元
  (所以,我们可以根据上述公式,将除法转化为乘法。)

性质

  1. 存在唯一性

    证明:假设存在a′′也满足a×a′′≡1(mod p) 
    则有a×a′≡a×a′′(mod p)
    ∴a′ ≡ a′′(modp)
    矛盾。
    
  2. 完全积性函数 (把 a 的逆元表示为 inv[a] )

    ∀a,b∈N,inv[a]×inv[b]≡inv[a×b](mod p)
    证明: 
    ∵ a×inv[a]≡1(mod p),b×inv[b]≡1(mod p)
    ∴(a×b)×(inv[a]×inv[b]) ≡ 1×1 = 1(modp)
    由【性质1】知(a×b)的逆元只有一个。 
    ∴inv[a×b]≡inv[a]×inv[b](mod p)
    
  3. a*inv[b]=a/b(mod p) (灰常重要的一个结论哦)

    证明: 
     ∵ b×inv[b] ≡ 1(mod p)
     ∴  a × b × inv[b] ≡ a (mod p)
     ∴  a × inv[b] ≡ a / b(mod p)
    

求解

  1. 费马小定理(p是质数)
       a(p-1) ≡ 1(mod p)
       ∴ a × a(p-2) ≡ 1(mod p)
       ∴ a(p-2) 是 a 的乘法逆元
	const int p=1e9+7;   // 一个质数 
	Fermat(int a,int x)  //  x=p-2  // 一个快速幂啊
	{
		long long s=1;
		while(x)
		{
			if(x&1) s=(s+a)%p;
			a=(a*a)%p;
			x=x>>1;
		}
	}
  1. 扩展欧几里得算法 (p可以是任意整数)

    ax ≡ 1 (mod p) 可以等价的转化为  ax−py=1
    
    设当前状态为gcd(a,b)
    ① 当b = 0时,gcd(a,b)= a
         ∴ x=1,y=0;
    ② 当b ≠ 0时,先执行gcd(b,a mod b)
     	 ∴ x × b + y (a mod b) = 1 
     	 ∴ y × a + [ x−(a / b)y ] b = 1  
     	 然后构造x′,y′作为新的x,y满足ax+by=1 
     	 那么就可以使 x′=y,y′= x−(a / b)y
    
int a,p,x,y;
void exgcd(int a,int b)
{
	int xx,yy;
	if(!b)
	{
		x=1,y=0;
		return;
	}
	exgcd(b,a%b);
	xx=x , yy=y;
	x=xx , y=yy*(a/b)-xx;
	x=x%p , y=y%p;
}
int main()
{
	scanf("%d%d",&a,&p);
	exgcd(a,p);
	printf("%d\n",(x+p)%p);
	return 0;
}
  1. 欧拉函数
       ϕ(m) 表示小于m且与m互质的正整数的个数。
       如果a和m互质,则有aϕ(m) ≡ 1(mod m )
         ∴ a × a(ϕ(m) - 1) ≡ 1(mod m )
       在m为质数的情况下,ϕ(m) = m−1,即为费马小定理。
  • 对于任意整数n,可以将它分解 n=p1k1∗p2k2∗p3k3…pmkm,其中pi为质数其中ϕ(n)=ϕ(p1k1)∗ϕ(p2k2)…ϕ(pmkm)
    最后转化为ϕ(n)=n∗∏(pi − 1) / pi
int vis[N],p[N],n,tot,phi[N];
void eurler_phi()
{
	vis[1]=1;
	phi[1]=1;
	for(int i=2; i<=n; i++)
	{
		if(!vis[i])
		{
			p[tot++]=i;
			phi[i]=i-1;
		}
		for(int t=0; t<tot; t++)
		{
			int j=p[t]*i;
			if(j>n) break;
			vis[j]=1;
			phi[j]=phi[p[t]]*phi[i];
			if(i%p[t]==0)
			{
				phi[j]=p[t]*phi[i];
				break;
			}
		}
	}
}
int main()
{
	scanf("%d",&n);
	eurler_phi();
	for(int i=1; i<=n; i++) printf("%d\n",phi[i]);
}

  1. 递推法 (1~n在mod p 意义下的逆元)
    ∵ 1-1 ≡ 1 (mod p)
    ∴ 设 p = k × i + r ≡ 0 (mod p)
    ∴ 两边同时乘上 r-1 + i-1 , 得:
                  k × r-1 + i-1 ≡ 0 (mod p)
    ∴ i-1 ≡ - k × r-1 (mod p)
    ∴ i-1 ≡ - [ p / i ] × (p mod i)-1
	inv[i]]=1;
    inv[i]=(p-p/i)*inv[p%i]%p;

5. 欧拉筛法 (批量) (a 为合数,完全积性函数O(1)解决。)

  完全积性函数

int p;
int vis[N],pri[N];
int inv[N];
int ksm(int a,int x)  // 快速幂
{
	long long s=1;
	while(x)
	{
		if(x&1) s=(s+a)%p;
		a=(a*a)%p;
		x=x>>1;
	}
}
int main( )
{
	scanf("%d",&p);
	vis[1]=1,inv[1]=1;
	for(int i=2; i<p; i++)
	{
		if(!vis[i]) pri[++pri[0]]=i,inv[i]=mi(i,p-2);
		for(int j=1; j<=pri[0]; j++)
		{
			if(i*pri[j]>=p) break;
			inv[i*pri[j]]=inv[i]*inv[pri[j]];
			if(i%pri[j]==0) break;
		}
	}
	for(int i=1; i<p; i++)
		printf("inv[%d] = %d\n",i,inv[i]);
	return 0;
}

总结

#include<bits/stdc++.h>
using namespace std;
int inv[1000010];
int ksm(int a,int b,int mod)
{
	int ans=1;
	while(b)
	{
		if(b&1) ans=(ans*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return ans;
}
int exgcd(int a,int b,int &x,int &y)
{
	if(!b)
	{
		x=1;
		y=0;
		return a;
	}
	int GCD=exgcd(b,a%b,x,y);
	int tmp=x;
	x=y;
	y=tmp-a/b*y;
	return GCD;
}

int inv1(int a,int mod)  //扩展欧几里得
{
	int x,y;
	int d=exgcd(a,mod,x,y);
	if(d==1) return (x%mod+mod)%mod;
	return -1;
}

int inv2(int a,int mod) //费马小定理
{
	return ksm(a,mod-2,mod);
}

void inv3(int mod)//线性递推求逆元
{
	inv[1]=1;
	for(int i=2; i<=mod-1; i++)
	{
		inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		cout<<inv[i]<<" ";
	}
}

int main()
{
	int n,mod;
	scanf("%d%d",&n,&mod);
	printf("%d\n",inv1(n,mod));
	printf("%d\n",inv2(n,mod));
	printf("%d\n",inv3(mod));
}

给我自己鼓掌
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值