逆元inv详细整理

个人笔记,仅供复习

1.概念

1.1 定义:逆元素是指一个可以取消另一给定元素运算的元素,在数学里,逆元素广义化了加法中的加法逆元和乘法中的倒数。

1.2 数论中定义:如果满足公式,a*b = 1(mod P),则a是b的逆元,同时b也是a的逆元。

1.3 另一种定义:a*x  = 1 (mod P),其中a与P互质,则称x的最小整数为a关于P的逆元。

2.逆元的应用

2.1 除法模运算:设c为b在对P取模状态下的逆元,在求(a/b)%P时,很可能会因为b过大而超过精度范围,这时候可以将除法转换成乘法来做,(a/b)%P = (a*b)%P = (a%P)*(b%P)%P

3.求逆元的常用方法

3.1 费马小定理

费马小定理:若p为素数,则有a^{p-1}\equiv1(mod P)

推论:a*a^{p-2}\equiv 1(mod P)

a^{p-2}就是a关于P的一个逆元

3.1.1代码实例:

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 100010;
const int Mod = 1e5+7;
typedef long long LL;
LL Finv[maxn];
LL Qpow(LL x,LL p,LL m){//快速幂算法 
	LL res = 1;
	while(p){
		if(p&1)	res =res*x%m;
		x = x*x%m;
		p >>= 1;
	}
	return res;
}
void Init(){//用来求逆元 
	Finv[1] = 1;
	for(int i = 2;i < maxn;i++)
		Finv[i] = Qpow(i,Mod-2,Mod);
}
int main()
{
	Init();
	for(int i = 1;i < maxn;i++)
		cout << Finv[i] << " ";
	return 0;
}

3.1.2 复杂度分析:求单个逆元的时间复杂度是lg(Mod)

3.2 拓展欧几里得算法

求a关于1模P的逆元a\equiv 1(mod P),可以转化为a*X = 1+K*P,其中X与P都是整数,这样X即为所求逆元。

这样就可以转化为拓展欧几里得算法(要求a与P互质):a*X + K*P = 1;

3.3 逆元线性筛

递推式:inv[i] = (Mod-Mod / i) * inv[Mod% i]%Mod

推倒:假设t = Mod / i(向下取整),k = Mod % i,那么t * i + k = Mod;

因为 t*i+k \equiv 0(mod Mod)

等式两边同时除 i * k,得:

t*k^{-1} + i^{-1} \equiv 0(mod Mod)

移项,得:

i^{-1} \equiv t*k^{-1} (mod Mod);

inv[i] = (-Mod/i)*inv[Mod% i]%Mod

如果要保证结果为正: inv[i] = (Mod-Mod / i) * inv[Mod% i]%Mod

3.3.1 代码实例:

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long LL;
const int maxn = 100010;
const int Mod = 1e5+7;
LL inv[maxn];
void Inv(){
	inv[0] = inv[1] = 1;
	for(LL i = 2;i < maxn;i++){
		inv[i] = (Mod - Mod/i)*inv[Mod%i]%Mod;
	}
}
int main()
{
	Inv();
	return 0;
}

3.3.2 算法复杂度分析:线性时间递推,时间复杂度O(lg n)

3.3.3 求 n! 逆元:

inv[i] = inv[i+1] * (i + 1) % Mod

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 100010;
const int Mod = 1e9+7;
typedef long long LL;
LL Finv[maxn],F[maxn];//F存阶乘,Finv存对应逆元 
LL Qpow(LL x,LL p,LL m){ 
	LL res = 1;
	while(p){
		if(p&1)	res =res*x%m;
		x = x*x%m;
		p >>= 1;
	}
	return res;
}
void Init(){
	F[0] = 1;
	for(LL i = 1;i < maxn;i++)
		F[i] = F[i-1]*i%Mod; 
	Finv[maxn-1] = Qpow(F[maxn-1],Mod-2,Mod);
	for(int i = maxn-1;i > 0;i--)
		Finv[i-1] = Finv[i]*i%Mod;
}
int main()
{
	Init();
	for(int i = 1;i < maxn;i++)
		cout << Finv[i]*F[i]%Mod << "\t";
	return 0;
}

 

转载于:https://www.cnblogs.com/long98/p/10352177.html

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值