c++ 乘法逆元

主要参考:OI-WIKI

为什么要逆元

当一个题目让你求方案数时常要取余,虽然
(a+b)%p=(a%p+b%p)%p
(ab)%p=(a%pb%p)%p
(a×b)%p=(a%p×b%p)%p
但是
(ab)%p(a%pb%p)%p
由于会出现这种情况,所以就要逆元了
一般情况下,当ax=1时,x 是 a 的倒数,x=1a
毕竟是取余,所以当ax1(modp)时, x 叫做 a 关于 p 的逆元,用 a1 表示
于是 (ab)%p=(a%p×b1%p)%p
这样就把除法转换成乘法,解决了问题

如何求逆元

前提:gcd(a,p)=1 (本蒟蒻现在才发现模数这么奇怪原来有意图,如

费马小定理

apa(modp)ap21a(modp)
证明:OI-WIKI(蒟蒻不会)
所以说a1ap2(modp)
复杂O(logp)

扩展欧几里得

ax+py=1的一组解 (x,y) ,x 是 a 关于 p 的逆元, y 是 p 关于 a 的逆元
证明:两边同时模 p
           ax+py=1ax%p+py%p=1%p               ax%p=1%p                    ax1(modp)
所以 x 是 a 关于 p 的逆元,反之可以证明 y
复杂O(logp)

连续的逆元

连续的逆元

如果直接暴力求,效率低,很有可能超时,如何线性(O(n))求呢?

首先 111(modp)
然后,设 p=ki+r,r<i,l<i<p ,放到(modp) 下就成了 ki+r0(modp)
两边同时乘上i1r1可得
kii1r1+ri1r10(modp)
                             kr1+i10(modp)
                                              i1kr1(modp)
                                              i1ip(pmodi)1(modp)
于是就可以从前面推出当前的逆元了,A[1]=1,A[i]=(pp/i)A[p%i]
ppi防止出现负数,时间复杂度O(n)


阶乘的逆元

可以先处理 n! 的逆元,可以发现对于一个 1i<n,都有1i!=1(i+1)!(i+1)
所以 i!的逆元A[i]=A[i+1](i+1)%p,A[n] 先求出来,时间复杂度O(logp+n)

求任意 n 个数的逆元

先算出前缀积 si 并预处理出 sn 的逆元 svn
与阶乘的逆元相同,svi=svi+1ai+1%p,1i<n 用这种抵消的方法可以O(n)处理出sv
求出了svai1可以用si1svi求得,时间复杂度O(logp+n)

本文作者:小蒟蒻laf

本文链接:https://www.cnblogs.com/KonjakLAF/p/14224309.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   小蒟蒻laf  阅读(720)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起