下面设要求逆元的数是 n ,对 mo 求逆元。
费马小定理
当模数为质数才能用。 逆元为:\(n^{(mo-2)}\%mo\),快速幂可以解决。Time: \(O(log\,mo)\)一般\(mo=1000000007\)或\(998244353\)时,\(log\,mo\)大约是30。
Ex_gcd
模数不为质数也可以用。 求解 exgcd(n,mo,x,y),得到的x就是逆元。Time和费马小定理一样。
注意求解完建议 x=(x+mo)\%mo
。怕x是负数或者大于mo。(但是似乎x不会小于 -mo ,我也不清楚,保险可以加个while什么的)
线性求逆元
有递推公式如下:
inv[i]=mo-(mo/i)*inv[mo%i]%mo;
Time:\(O(n)\)
坏处:时间慢,n过大时数组存不下
好处:可以求出1~n所有逆元,所以建议求多次逆元时使用
不过好像如果数组存不下,可以用递归+记忆化(比如你数组能开十万,你就把十万内的逆元记下来,其它的就递归硬算)跑起来挺快的
#include<bits/stdc++.h>
using namespace std;
int mo=998244353;
int n,inv[10000007];
int do_inv(int z){
if(z<=10000000){//数组能开多大就开多大
if(inv[z]!=-1)return inv[z];
inv[z]=mo-(mo/z)*do_inv(mo%z)%mo;
return inv[z];
}
else return mo-(mo/z)*do_inv(mo%z)%mo;
}
int main(){
memset(inv,-1,sizeof inv);
inv[1]=1;
while(cin>>n)cout<<do_inv(n)<<endl;
}