【模板】乘法逆元

前往:我自己搭建的博客

题目

洛谷P3811乘法逆元

题解

定义:乘法逆元又称数论倒数。若  且a,m互质,则x为a的逆元,记为,若a,m不互质,则不存在逆元。当且仅当m为素数时,a有唯一的乘法逆元。

用途:在模算术中,有以下几个公式:

(a+b) mod p =((a mod p)+(b mod p)) mod p

(a-b) mod p=((a mod p) – (b mod p) + p) mod p

ab mod p=(a mod p)(b mod p)mod p

在模意义下的运算中,这几个公式可以降低运算过程中数据的规模,然而,遇到除法运算时,便会出现问题。下面是个错误的式子:a/b mod p=(a mod p)/(b mod p) mod p 可以举例证伪。在一系列模运算中,被除数和除数可能进行过取模操作,因此无法直接得到正确结果。因此,模意义下的除法要转化成乘法。

一个例子:6/2=3(mod 5) 6*3=3(mod 5)

求逆元方法一(费马小定理):

费马小定理:若p是质数,则对于任意整数a,有 

结合快速幂就可以求逆元。缺陷:这种算法必须保证p是质数,而且复杂度较高,不适合批量操作。

#include 
using namespace std;
typedef long long ll;
ll n,p; 
inline ll quick_pow(ll a,ll b)
{
	ll ans=1;
	for( ;b;b>>=1)
	{
		if(b&1) ans=ans*a%p;
		a=a*a%p;
	}
	return ans;
}

int main()
{
	scanf("%lld%lld",&n,&p);
	for(ll i=1;i<=n;i++) printf("%lld\n",quick_pow(i,p-2));
	
	return 0;
}

求逆元方法二(扩展欧几里得算法):即求同余方程  的解(通常求最小正整数解)。这个算法只要求a,p互质,速度也更快,但也不适合批量操作。

#include 
using namespace std;
typedef long long ll;
ll n,p,x,y;
void exgcd(ll a,ll b,ll &x,ll &y)
{
	if(!b) {x=1,y=0; return;}
	exgcd(b,a%b,x,y);
	ll z=x; x=y; y=z-(a/b)*y;
}

int main()
{
	scanf("%lld%lld",&n,&p);
	for(ll i=1;i<=n;i++) 
	{
		exgcd(i,p,x,y);
		x=(x%p+p)%p;
		printf("%lld\n",x);
	}
	
	return 0;
}

求逆元方法三(线性递推):推导过程如下(第2行到第3行,两边同时乘i和p mod i的逆元)

【模板】乘法逆元_第1张图片

#include 
using namespace std;
typedef long long ll;
const int maxn=3e6+5;
ll n,p;
ll inv[maxn]; //inv[i]表示i的逆元 

int main()
{
	scanf("%lld%lld",&n,&p);
	inv[1]=1; printf("1\n");
	for(ll i=2;i<=n;i++) 
	{
		inv[i]=(p-p/i)*inv[p%i]%p;
		printf("%lld\n",inv[i]);
	}
	
	return 0;
}

你可能感兴趣的:(【模板】乘法逆元)