[數學/數論] 普通求逆

網上的求逆方法普遍長這樣

a[1]=1;
for(int i=2;i<=n;++i) a[i]=(mod-(mod/i))%mod*a[mod%i]%mod;

下面介紹一種簡單且萬能的

pr[1]=1;
for(int i=2;i<=n;++i) pr[i]=pr[i-1]i%mod;
b[n]=qpow(pr[n],mod-2);
for(int i=n-1;i;–i) b[i]=b[i+1]
(i+1)%mod;
b[1]=1;
for(int i=2;i<=n;++i) b[i]=b[i]*pr[i-1]%mod;

講解開始

逆元的定義

(modp)\pmod p意義下,i×i11i\times i^{-1}\equiv1,則iii1i^{-1}互爲逆元

使用逆元的意義:爲了保證精度,維護整數問題(即數論問題)的過程中,不能除,於是利用與原數積在模意義下爲1的數,來替代除法

an=na_n=n的逆元求法

常用,但是常數有點大

推導:
p,ip=ki+r(k=pi,r=pmodi)ki+r0(modp)i1r1(ki+r)0(modp)i1+kr10(modp)i1kr1(modp)r=pmodi,r<i,ir,11=1 \begin{aligned} &模p意義下,求i的逆元\\ &p=ki+r\quad(k=\lfloor\frac{p}{i}\rfloor,r=p\bmod i)\\ &ki+r\equiv 0\pmod p\\ &i^{-1}r^{-1}(ki+r)\equiv 0\pmod p\\ &i^{-1}+kr^{-1}\equiv 0\pmod p\\ &i^{-1}\equiv -kr^{-1}\pmod p\\ &由於r=p\bmod i,則r<i,求i時r已求出,可以遞歸求解\\ &邊界1^{-1}=1 \end{aligned}

Code

a[1]=1;
for(int i=2;i<=n;++i) a[i]=(mod-(mod/i))%mod*a[mod%i]%mod;

任意數列的逆元求法

常數又小,適用範圍又廣
不學他學誰?

推導
{an}(an=n),pri=j=1iaj,,invn=prnp2(prn)1i=1naiinvi=invi+1×ai+1,,invi=invi×pri1O(N) \begin{aligned} &對於\{a_n\}(通常是a_n=n的數列),記pr_i=\prod_{j=1}^ia_j,\\ &第一遍,inv_n=pr_n^{p-2}(即pr_n的逆元)\equiv\frac{1}{\prod_{i=1}^na_i}\\ &inv_i=inv_{i+1}\times a_{i+1},遞推下去\\ &第二遍,inv_i=inv_i\times pr_{i-1} \\\\&時間複雜度O(N) \end{aligned}

Code

pr[1]=1;
for(int i=2;i<=n;++i) pr[i]=pr[i-1]*i%mod;
b[n]=qpow(pr[n],mod-2);
for(int i=n-1;i;--i) b[i]=b[i+1]*(i+1)%mod;
b[1]=1;
for(int i=2;i<=n;++i) b[i]=b[i]*pr[i-1]%mod;

Tips

  1. 注意邊界:
    法一中inv[1]要賦初值
    法二中最後一層循環由於pr[0]=0,無法更新inv[1],那麼手動賦1
  2. 注意求逆元的範圍
    想清楚就行了
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章