乘法逆元
引入
我们知道,模意义下没有同除性。
也就是说,我们无法直接完成除法。怎么办?
考虑使用乘另一个数代替除一个数。
乘法逆元
定义:若一个数 \(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}\),有
故 \(a\) 在模 \(b\) 意义下的逆元即为 \(x=a^{p-2}\) 次方。
不理解的话结论也是很好记得罢。
局限性:要求模数 \(b\) 为质数。
Exgcd 求逆元
见我的这篇博文。
线性求 \([1,n]\) 所有数的逆元
若当前数为 \(i,i\in[1,n]\),求模 \(p\) 意义下的逆元(\(p\) 可不为质数),设
于是有
同时
两边同乘以 \(i^{-1}\times r^{-1}\),
将 \((3)\) 代入 \((5)\)
根据式 \((6)\),即可递推求逆元了。当然,它也可以单个求解,递归即可,复杂度 \(O(\log p)\),请读者自证。
为防止出现负数,一般改写为以下形式
代码
#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}\)。
于是利用前缀/差分的思想,巧妙地解决了问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探