1. 程式人生 > >線性篩約數個數、約數和的新方法

線性篩約數個數、約數和的新方法

n) http 約數 質因子 9.png int pan 思考 -s

最近本人腦洞大開,發現了一種線性篩約數個數和約數和的一種神奇方法。

網上的方法我看基本都是利用num[i]數組記錄i最小的質因子的個數,然後再搞搞。

我認為可以省去num[i]數組,直接進行遞推。

我們知道,n的標準分解式為:

技術分享圖片

那麽n的約數個數及約數和分別為:

技術分享圖片

對於線性篩函數f(i),只需要知道4個東西。

1:f(1) = ?

  很顯然,d(1) = 1,o(1) = 1;

2:f(p) = ?,其中p為質數。

  同樣很顯然,d(p) = 2,o(p) = p+1;

3、4:f(i*pj) = ?,i與pj互質或不互質。

若i與pj互質,則我們可以利用積性函數的性質直接推出:

技術分享圖片

最後思考當i與pj不互質的時候,考慮i,i*pj,i/pj的關系(i與pj不互質即i%pj==0)

設:

技術分享圖片

則有:

技術分享圖片

進行換元方便計算,設:

技術分享圖片就是把pj那一項去掉

則有:

技術分享圖片

將第一個式子與第二個相減,得到:

技術分享圖片

那麽就已經出來了,

技術分享圖片

同理,約數和也可以像這樣推出來。

補上代碼:

int pr[N],vis[N],d[N],sigma[N],cnt;
void make(int n)
{
    d[1] = sigma[1] = 1;
    for(int i = 2;i<=n;i++)
    {
        if(!vis[i])pr[++cnt] = i,d[i] = 2,sigma[i] = i+1;
        for(int j = 1;i*pr[j]<=n&&j<=cnt;j++)
        {
            vis[i
*pr[j]] = 1; if(i%pr[j]==0) { d[i*pr[j]] = d[i]*2-d[i/pr[j]]; sigma[i*pr[j]] = pr[j]*(sigma[i]-sigma[i/pr[j]])+sigma[i]; break; }d[i*pr[j]] = d[i]*2; sigma[i*pr[j]] = sigma[i]*(pr[j]+1); } }
for(int i = 1;i<=n;i++)printf("%d %d\n",d[i],sigma[i]); }

線性篩約數個數、約數和的新方法