乘法逆元

引入

我们知道,模意义下没有同除性。

也就是说,我们无法直接完成除法。怎么办?

考虑使用乘另一个数代替除一个数。

乘法逆元

定义:若一个数 \(x\) 满足 \(ax\equiv 1\pmod b\),那么称 \(x\) 为模 \(b\) 意义下 \(a\) 的乘法逆元,记为 \(a^{-1}\)

以下简称乘法逆元为逆元。

快速幂-费马小定理

费马小定理:对于 \(p\in\Bbb{P},a\in\Bbb{Z}\),有 \(a^p\equiv a\iff a^{p-1}\equiv 1\pmod p\)

\(b\in\Bbb{P}\),有

\[\begin{aligned} ax&\equiv 1\pmod b\\ ax&\equiv a^{b-1}\pmod b\\ x&\equiv a^{b-2}\pmod b \end{aligned}\tag{1} \]

\(a\) 在模 \(b\) 意义下的逆元即为 \(x=a^{p-2}\) 次方。

不理解的话结论也是很好记得罢。

局限性:要求模数 \(b\) 为质数。

Exgcd 求逆元

见我的这篇博文

线性求 \([1,n]\) 所有数的逆元

若当前数为 \(i,i\in[1,n]\),求模 \(p\) 意义下的逆元(\(p\) 可不为质数),设

\[p=k\times i+r\tag{2} \]

于是有

\[\begin{cases} k=\left\lfloor\cfrac{p}{i}\right\rfloor\\ r=p\bmod i \end{cases}\tag{3} \]

同时

\[k\times i+r\equiv 0\pmod p\tag{4} \]

两边同乘以 \(i^{-1}\times r^{-1}\)

\[\begin{aligned} k\times r^{-1}+i^{-1}&\equiv 0&\pmod p\\ i^{-1}&\equiv -k\times r^{-1}&\pmod p \end{aligned}\tag{5} \]

\((3)\) 代入 \((5)\)

\[i^{-1}\equiv -\left\lfloor\cfrac{p}{i}\right\rfloor\times(p\bmod i)^{-1}\tag{6} \]

根据式 \((6)\),即可递推求逆元了。当然,它也可以单个求解,递归即可,复杂度 \(O(\log p)\)请读者自证

为防止出现负数,一般改写为以下形式

\[i^{-1}\equiv \left(p-\left\lfloor\cfrac{p}{i}\right\rfloor\right)\times(p\bmod i)^{-1}\tag{7} \]

代码

#include <iostream>
using namespace std;

typedef long long ll;
ll n,p;

ll inv[3114514];
void init()
{
	inv[1]=1ll;
	printf("1\n");
	for(ll i=2;i<=n;i++)
	{
		inv[i]=(p-(p/i))%p*inv[p%i]%p;// 注意正负、取模
		printf("%lld\n",inv[i]);
	}
}

int main()
{
	scanf("%lld %lld",&n,&p);
	init();
	return 0;
}

线性求任意 \(n\) 个数的逆元

更加一般化的求逆元法。

设这 \(n\) 个数为 \(a_i,i\in[1,n]\),它们的前缀积为 \(s_i=\prod_{j=1}^{i} a_i\) 及其逆元 \(sinv_i=(s_i)^{-1}\)

显然 \(s_i\) 可以 \(O(n)\) 算出,且 \(sinv_n=(s_n)^{-1}\) 也可以 \(O(\log p)\) 用之前的方法求出。

接着倒序遍历每个 \(sinv_i,i\in[1,n)\)\(sinv_i=sinv_{i+1}\times a_{i+1}\)。这样就抵消了 \((a_{i+1})^{-1}\)

于是对于每个数 \(a_i\),其逆元 \((a_i)^{-1}=sinv_{i}\times s_{i-1}\)

于是利用前缀/差分的思想,巧妙地解决了问题。

posted @ 2024-01-06 14:59  Po7ed  阅读(7)  评论(0编辑  收藏  举报