算法学习笔记-逆元
前言:
还记得小学学的倒数吗?倒数的定义大概是若
例题:
给定正整数
保证
解法:
1.费马小定理:
费马小定理的定义:
对于任意正整数
可以发现,费马小定理的式子很像逆元,考虑把它转化一下,变成:
可以发现,
点击查看代码
int qpow(int a, int b, int mod)
{
int ans = 1;
a %= mod;
while(b)
{
if(b & 1) ans *= a;
a = a * a % mod;
b >>= 1;
}
return ans;
}
int inv(int a, int p)//求a在模p意义下的乘法逆元
{
return qpow(a, p - 2, p);
}
2. :
不知道
考虑将原式转换为
点击查看代码
void exgcd(int a, int b, int &x, int &y)
{
if(b == 0)
{
x = 1; y = 0;
return;
}
exgcd(b, a % b, y, x);
y = a / b * x;
}
int inv(int a, int p)//求a在模p意义下的乘法逆元
{
int x, y;
return exgcd(a, p, x, y);
}
3.线性递推:
很多时候,题目要求的都是像例题那样
注:下面笔者提供了两种介绍方法,前一种为严谨的数学证明,后一种是转化为
- 数学证明:
先给结论:
先把式子转化一下:
设
则
则原式就可以变成:
打开括号,变成:
把
因为对于同余方程,增减带模数的项结果不发生改变,所以可以将
换句话说,
- 其实仔细观察可以发现,上式其实与
的结论的式子很像。加上之前逆元对 的转化,就显而易见了,具体一点笔者也说不清,请读者自行脑补(大雾。
知道上面的结论,代码就好写了。用一个数组记录每个数的逆元,正序枚举,由于枚举到
1
点击查看代码
inv[1] = 1;//inv[i] = i^ -1
cout << 1 << "\n";
for(int i = 2; i <= n; i++)
{
inv[i] = (p - p / i) * inv[p % i] % p;//按公式计算。
//之所以要p-p/i是因为除完之后是个负数,在后面的取模会有问题,因此按照负数取模的原理要减一下
cout << inv[i] << "\n";
}
总结:
至此,逆元就告一段落了,文中的三种方法都有不错的时间复杂度,在应用中请根据实际情况选择,希望本文能帮助到您。
鉴于笔者也是蒟蒻,文中给出的部分推导过程与表述可能不严谨,欢迎大佬在评论区指出。
同时如果您对文章内容有不理解的地方,欢迎随时提问。
本文来自博客园,作者:zhangxiao666,转载请注明原文链接:https://www.cnblogs.com/zhangxiao666qwq/p/suanfa-niyuan.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!