【算法学习】逆元与求解
1.【算法学习】排序2.【算法学习】Manacher 马拉车3.【算法学习】KMP 算法4.LCA 最近公共祖先(树链和倍增)这次真有树链了!!!5.线段覆盖问题6.【算法学习】学换根dp有感7.二分图最大匹配8.【算法学习】01BFS9.洛谷 P1892 [BOI2003] 团伙 种类并查集 扩展域并查集10.【算法学习】高斯消元法11.贝叶斯公式12.背包13.【算法学习】模拟退火14.【算法学习】基环树15.【算法学习】树链部分16.【算法学习】莫队17.【算法学习】分块九讲18.平衡树19.圆方树20.【算法学习】点分治21.公式22.【算法学习】笛卡尔树23.【算法学习】悬线法24.欧几里得算法与 EX
25.【算法学习】逆元与求解
26.【算法学习】费马定理27.三分28.裴蜀定理29.【算法学习】欧拉函数φ30.【算法学习】二维转一维问题31.【算法学习】扫描线32.【算法学习】矩阵乘法33.【算法学习】同余最短路34.【算法学习】组合数学35.【算法学习】反悔贪心逆元
当 \(ax\equiv1\ (mod \ b)\) 称 \(x\) 为 \(a \mod b\) 的逆元,记作 \(a^{-1}\)。
求逆元
以下都是求逆元的方法,为了不那么无聊 给个例题做。
拓展欧几里得法
虽然 exgcd 是为了求 \(ax+by=gcd(a,b)\),但是 \(ax\equiv1\ (mod \ b)\) 这个式子代表着 \(a\) 和 \(b\) 互质,即 \(gcd(a,b)=1\),所以他们是可以相互转化的,\(y\) 也通常是非正数。
然后直接 exgcd 即可。
时间复杂度 \(O(\log \min(a,b))\)
链接里面有啊
#include <bits/stdc++.h> using namespace std; #define ll long long void exgcd(ll a,ll b,ll &x,ll &y){ if(b==0){ x=1,y=0; return; } exgcd(b,a%b,y,x); y-=a/b*x; } int main(){ ios::sync_with_stdio(false); ll a,b; cin>>a>>b; for(ll i=1;i<=a;i++){ ll d=__gcd(i,b); ll x,y; exgcd(i,b,x,y); x=(x%b+b)%b; cout<<x<<"\n"; } return 0; }
快速幂法
\(\because ax \equiv1\ (mod\ b)\)
\(\therefore ax \equiv a^{b-1}\ (mod\ b)\) (费马小定理)
\(\therefore x \equiv a^{b-2}\ (mod\ b)\)
此时直接快速幂模 \(b\) 即可。
时间复杂度 \(O(\log b)\)
非常简单还要看吗?
#include <bits/stdc++.h> using namespace std; #define ll long long const int N=10005; ll a,b; ll quickpow(ll x,ll k,ll mod){ ll sum=1; while(k){ if(k&1){ sum*=x; sum=(sum+mod)%mod; } x*=x; x=(x+mod)%mod; k>>=1; } return sum; } int main(){ ios::sync_with_stdio(false); int t; cin>>t; while(t--){ cin>>a>>b; if(a%b==0){//并不互质,不合法 cout<<"impossible\n"; } else{ cout<<quickpow(a,b-2,b)<<"\n"; } } return 0; }
线性求逆元
这个方法只适用于这道例题要求出 \(1-a\) 全部数的逆元。
初始化有 \(1^{-1} \equiv1 (\mod b)\)
设 \(b=k\times i+r,(1<r<i<b)\),\(k\) 为 \(p/i\) 的商,\(r\) 是余数。
把这个式子在 \((mod\ b)\) 的意义下得到:
\[k\times i+r \equiv 0 (mod\ b)
\]
都乘上 \(i^{-1},r^{-1}\) 可以得到:
\[k\times r^{-1}+i^{-1} \equiv 0 (\mod b)
\]
\[i^{-1}\equiv -k\times r^{-1} (mod\ b)
\]
\[i^{-1}\equiv -\lfloor \frac{b}{i} \rfloor \times (b\ mod\ i)^{-1} (mod\ b)
\]
于是,我们就可以递推得到当前的逆元了。
RT
#include <bits/stdc++.h> using namespace std; #define ll long long ll a,b; ll inv[3000006]; int main(){ ios::sync_with_stdio(false); cin>>a>>b; inv[1]=1; cout<<"1\n"; for(int i=2;i<=a;i++){ inv[i]=((0-(b/i)*inv[b%i])%b+b)%b; cout<<inv[i]<<"\n"; } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)