乘法逆元总结(求法及递推式)
2019-04-14 09:08发布
生成海报
乘法逆元
(一)、定义。
对于正整数和,如果有,
那么把这个同余方程中的最小正整数解叫做模的逆元。
个人理解:
在一些题目中,经常因为数据过大,题目要求结果要模除一个数,常见的mod=1e9+7 (素数)
有时候,代码运算过程中会用到除法,而所有数据都已经模除了mod,导致除法可能会失真。
比如在mod=14的情况下,我要求25/5的值(理应是5),但是这里的25早已经不是25,
而是25%mod=11,
这时候得到的值其实是11/5=2,已经不是正确值5了。
这种时候乘法逆元就横空出世了。。
先声明,我要求的 a/b 是在整数范围内进行的,也就是b能整除a,乘法逆元才适用
意义:
上面的例子中,a=25,b=5.a/b=5。而mod=14,a在模除了mod之后再计算a/b的结果是错的。
有逆元的前提是,b和mod是互质的。
想得到正确结果,假设b关于mod的逆元为inv。
那么:
a/b = (a*inv)%mod;(公式,不做证明了)
也就是把a除以一个数,化作了a乘以一个数。
b和inv的关系是
(b*inv)%mod=1;是不是有点像倒数
(二)、求逆元的方法。
1、拓展欧几里得
求b关于mod的逆元。
由于b与mod互质,即最大公约数为1。那么对于 b*x + mod*y = 1
存在一个最小的正整数x,这个x就是b关于mod的逆元
拓展欧几里得个人总结:点击打开链接
求b关于mod的逆元:
#include
int exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y=y-a/b*x;
return d;
}
int inv(int b,int mod)//求b关于mod的逆元
{
int x,y;
exgcd(b,mod,x,y);
return (x%mod+mod)%mod;
}
int main()
{
int b, mod=14;
while(~scanf("%d",&b))
{
printf("b关于mod的逆元:%d
",inv(b,mod));
}
return 0;
}
2、费马小定理
在mod是素数的情况下,对任意整数
b 都有bp≡b(mod)p
即
如果b无法被mod整除,则有
(b的(mod-1)次幂)%mod=1
(b * b的mod-2次幂)%mod=1;
所以b的mod-2次幂%mod,就是b关于mod的逆元
上面这串话,我理解不了。
反正公式就是:
b关于mod的逆元 inv = (b的mod-2次幂)%mod;
求b关于mod的逆元(mod必须是素数才可以)
#include
int qpow(int x,int m,int mod)//快速幂,求x的m次方
{
int ans=1;
while(m)
{
if(m%2)
ans=(ans*x)%mod;
x=(x*x)%mod;
m=m/2;
}
return ans;
}
int inv(int b,int mod)//求b关于mod的逆元
{
return qpow(b,mod-2,mod);
}
int main()
{
int b, mod=17;
while(~scanf("%d",&b))
{
printf("b关于mod的逆元:%d
",inv(b,mod));
}
return 0;
}
3、递归求乘法逆元(应用了4、里面的递推公式)
#include
const int mod=17;
int inv(int b,int mod)
{
if(b==1)return 1;
return (mod-mod/b)*inv(mod%b,mod)%mod;
}
int main()
{
for(int i=1;i
4、递推求逆元。求1~mod-1之间所有数的逆元,递推公式。
(1)方法:
初始化1的逆元为1,即inv [ 1 ] = 1 , 正序递推。
inv [ i ] = (mod - mod/i)*inv[ mod%i ] %mod;
#include
int main()
{
int mod=17, Inv[100];
Inv[1]=1;
for(int i=2;i
(2)拓展一种求1~n!之间的数关于mod的逆元的递推(!表示阶乘)
方法:
先求出(mod-1)!的逆元,倒序递推。
inv [ i ] = (inv [ i+1 ]*(i+1))%mod;
原理不会。
#include
int qpow(int x,int m,int mod)//快速幂,求x的m次方
{
int ans=1;
while(m)
{
if(m%2)
ans=(ans*x)%mod;
x=(x*x)%mod;
m=m/2;
}
return ans;
}
int inv(int b,int mod)//求b关于mod的逆元
{
return qpow(b,mod-2,mod);
}
int fac(int t)
{
if(t==1)return 1;
return t*fac(t-1);
}
int main()
{
int mod=17, Inv[100];
Inv[mod-1]=inv(fac(mod-1),mod);//fac表阶乘,可以提前打表
for(int i=mod-2;i>0;i--)
Inv[i]=(Inv[i+1]*(i+1))%mod;
for(int i=1;i
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮