理論基礎:ide
一、對n質因數分解,n=p1^k1 * p2^k2 * p3^k3 ……函數
則n的約數個數爲(k1+1)*(k2+1)*(k3+1)……spa
二、線性篩素數時,用i和素數pj來篩掉 i*pj,code
其中pj必定是i*pj的最小素因子blog
若是i是pj的倍數,pj也是i的最小素因子io
設t[i] 表示i的約數個數,e[i] 表示i的最小素因子的個數event
A、若是i是質數,t[i]=2,e[i]=1class
B、若是i不是質數,枚舉已有的質數pj基礎
i*pj的最小素因子是pjcli
一、若是i是pj的倍數那麼e[i]即爲i中包含的pj的個數,因此i*pj中包含的pj的個數爲e[i]+1
因此e[i*pj]=e[i]+1,t[i*pj]=t[i]/(e[i]+1)*(e[i]+2)
二、若是i不是pj的倍數,e[i*pj]=1,t[i*pj]=t[i]*t[pj](積性函數的性質)=t[i]*2(素數的約數個數=2)
#include<cstdio> using namespace std; #define N 1000001 bool vis[N]; int prime[N]; int t[N],e[N]; int main() { int n; scanf("%d",&n); int cnt=0; t[1]=1; for(int i=2;i<=n;++i) { if(!vis[i]) { prime[++cnt]=i; t[i]=2; e[i]=1; } for(int j=1;j<=cnt;++j) { if(i*prime[j]>n) break; vis[i*prime[j]]=true; if(i%prime[j]==0) { t[i*prime[j]]=t[i]/(e[i]+1)*(e[i]+2); e[i*prime[j]]=e[i]+1; break; } else { t[i*prime[j]]=t[i]*2; e[i*prime[j]]=1; } } } long long ans=0; for(int i=1;i<=n;++i) ans+=t[i]; printf("%lld",ans); }
t[i] 表示i的約數和
e[i] 表示i的約數中,不能被i的最小素因子整除的約數和
A、i是質數,t[i]=i+1,e[i]=1
B、i不是質數
i*pj的最小素因子是pj
一、若是i不是pj的倍數,那麼i的全部約數中,必然沒有pj的倍數
能夠用反證法證實這個:設x是i的約數,且x是pj的倍數,
那麼 x=pj*b,i=x*a=pj*b*a
即i是pj的b*a倍,與i不是pj的倍數相矛盾
令S表示i的約數集,S’表示i的約數翻pj倍後的數的集合
則S∩S’=∅,則S和S’中無重複元素
因此t[i*pj]=S+S'=t[i]+t[i]*pj=t[i]*(pj+1)
S’中的全部元素都能整除pj,因此e[i*pj]=t[i]
二、若是i是pj的倍數,那麼S和S’必有交集T
T=S中pj的倍數
因此i*pj的約數和要去除交集T
那麼t[i*pj]=S+S'-T=S'+S-T=t[i]*pj+e[i]
由於pj既是i的最小素因子,有事i*pj的最小素因子
因此e[i*pj]=e[i]
#include<cstdio> typedef long long LL; #define N 100001 int prime[N]; bool vis[N]; LL t[N],e[N]; int main() { int n; scanf("%d",&n); int cnt=0; for(int i=2;i<=n;++i) { if(!vis[i]) { prime[++cnt]=i; t[i]=i+1; e[i]=1; } for(int j=1;j<=cnt;++j) { if(prime[j]*i>n) break; vis[prime[j]*i]=true; if(i%prime[j]==0) { t[i*prime[j]]=t[i]*prime[j]+e[i]; e[i*prime[j]]=e[i]; break; } t[i*prime[j]]=t[i]*(prime[j]+1); e[i*prime[j]]=t[i]; } } LL ans=0; for(int i=1;i<=n;++i) ans+=t[i]; printf("%lld",ans); }