线性求逆元模板_逆元Inv(模板+应用)

逆元:

如果满足公式

7d2daa49c318e232dbe2faf5dda2f647.gif,则有a 是 b的逆元同时b也是a的逆元。

逆元的应用:

设c为b在对m取余的意义下的逆元;

在求解公式 (a / b) % m的时候,如果b可能会非常的大,所以会出现爆精度的问题,这个时候就需要将除法转换成乘法来做,即:

(a / b )  % m = (a * c)%m。

逆元的求法:

一、扩展欧几里得求逆元

复杂度:O(logn)(实际就是斐波那契数列)

将公式(b、p已知)   a?b≡1(mod p)   转换为   a?b+k?p=1  则有a为b对p取余意义下的逆元,且只有当a与p互质是逆元才存在。

注意:只要存在逆元就可以求,适用于逆元个数不多,但是mod很大的时候。

附一个百度百科的例子加深一下理解:

2f4fe9efaf1dbff3b461ddf96b407bd5.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==?

代码:

/*Time:2018/8/31

Writer:Sykai

Function:利用扩展欧几里得求逆元*/#include#include#include#include#include

#define INF 0x3f3f3f3f

using namespacestd;const int maxn = 1e6 + 100;const int MOD = 1e9 + 7;

typedeflong longll;

typedef pairP;//公式a?b+k?p=1中a即是a,p即是b

ll exgcd(ll a,ll b,ll& x,ll&y)

{if(b == 0)

{

x= 1;

y= 0;returna;

}

ll res= exgcd(b, a%b, y, x);

y-= a/b*x;returnres;

}//公式a?b+k?p=1中a即是a,p即是mod

ll getInv(int a,int mod)//求a在mod下的逆元。如果不存在就返回-1

{

ll x,y;

ll res=exgcd(a,mod,x,y);return res = 1 ? (x%mod + mod)%mod:-1;//return res = 1?(x + mod)%mod : -1;

}intmain()

{

ll a= 5;

printf("%lld\n",getInv(a,MOD));return 0;

}

二、费马小定理求逆元

复杂度:O(logn)

费马小定理: 假如p是质数,且gcd(a,p)=1,那么 a^(p-1)≡1(mod p)。

a*a^(p-2) ≡ 1 (mod p),则有a^(p-2)是a的对p取余时候的逆元

注意:当p是素数的时候一般选用费马小定理来求逆元。

代码:

/*Time:2018/8/31

Writer:Sykai

Function:利用费马小定理求逆元*/#include#include#include#include#include

#define INF 0x3f3f3f3f

using namespacestd;const int maxn = 1e6 + 100;const int MOD = 1e9 + 7;

typedeflong longll;

typedef pairP;

ll qpow(ll a,ll b)//求a*a^(p-2) ≡ 1 (mod p)中a^(p-2)

{

ll res= 1;while(b)

{if(b&1)

res= res * a %MOD;

a= a * a %MOD;

b>>= 1;

}returnres;

}

ll getInv(ll a,ll mod)

{return qpow(a,mod-2);

}intmain()

{int a = 5;

printf("%lld\n",getInv(a,MOD));return 0;

}

三、递推求逆元

复杂度:O(n)

注意:

1、mod需要是质数,求得是1~N关于mod的逆元。

2、适用于mod不是太大,且被多次调用。

3、程序开始前需要预处理打表。

代码:

/*Time:2018/8/31

Writer:Sykai

Function:线性求逆元*/#include#include#include#include#include

#define INF 0x3f3f3f3f

using namespacestd;const int maxn = 1e6 + 100;const int MOD = 1e9 + 7;

typedeflong longll;

typedef pairP;

ll inv[maxn];//数组的大小需要根据实际情况来调整

voidgetInv()

{

inv[1] = 1;for(int i = 2; i < maxn; i++)

inv[i]= (MOD-MOD/i)*inv[MOD%i]%MOD;

}intmain()

{

getInv();

printf("%lld\n",inv[5]);return 0;

}

四、递归求逆元

复杂度:O(logn)

注意:mod需要是素数(中国剩余定理中不太好用)

/*Time:2018/8/31

Writer:Sykai

Function:递归求逆元*/#include#include#include#include#include

#define INF 0x3f3f3f3f

using namespacestd;const int maxn = 1e6 + 100;const int MOD = 1e9 + 7;

typedeflong longll;

typedef pairP;

ll inv[maxn];//数组的大小需要根据实际情况来调整

ll getInv(ll x)

{if(x == 1) return 1;return (MOD-MOD/x)*getInv(MOD%x)%MOD;

}intmain()

{

printf("%lld\n",getInv(5));return 0;

}

五、求阶乘的逆元

代码:(不确定怎么用)

/*Time:2018/8/31

Writer:Sykai

Function:递归求逆元*/#include#include#include#include#include

#define INF 0x3f3f3f3f

using namespacestd;const int maxn = 1e6 + 100;const int MOD = 1e9 + 7;

typedeflong longll;

typedef pairP;

ll inv[maxn];//数组的大小需要根据实际情况来调整

ll fac[maxn+1];//阶乘数组

ll qpow(ll a,ll b)

{

ll res= 1;while(b)

{if(b&1)

res= res * a %MOD;

a= a * a %MOD;

b>>= 1;

}returnres;

}intmain()

{

inv[maxn]= qpow(fac[maxn],MOD-2);for(ll i = maxn-1; i>=0; i--)

{

inv[i]= (inv[i+1]*(i+1))%MOD;

}return 0;

}

参考博客:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值