線性篩約數個數、約數和的新方法
阿新 • • 發佈:2019-02-17
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]); }
線性篩約數個數、約數和的新方法