一些重要的数论函数+线性筛模板
数论这块其实有好多函数,挺让人头疼的。
本篇主要讲解一些数论函数(欧拉函数、约数个数、约数和、莫比乌斯函数)以及它们的线性筛求法。
1.欧拉函数 φ(n)
欧拉函数φ(n)表示比n小的、且与n互质的正整数的数量。
如果把n分解成若干质因数之积的形式:n=(p1^a1)*(p2^a2)*...*(pk^ak)的话:
φ(n)=n*(1-1/p1)*(1-1/p2)*...*(1-1/pk)。
显然把不互质的都减掉,剩下的就是互质的。
这个可以通过分解质因数在O(sqrt(n))的时间内算出来。
线性筛法:
代码里我用phi表示欧拉函数。
计算的时候只需记录phi[n]即可。
可以把n*(1-1/p1)*(1-1/p2)*...*(1-1/pk)里的n拆成(p1^a1)*(p2^a2)*...*(pk^ak)分别乘进括号里。
这么说如果某质数p只有一次幂,贡献就是p-1(n拆分出来的一个p进括号,和1-1/p相乘后的结果)。
否则(p出现了多次),除了第一次是p-1,剩下的几次都是p(1-1/p已经用过了,没有东西能跟p相乘约掉了)。
显然i%pr[j]!=0的时候代表(i*pr[j])这个数中pr[j]只有一次幂。这样就能判断某个p是否是第一次出现了。
1 phi[1]=1; 2 for(int i=2;i<=n;i++) 3 { 4 if(!vis[i]) 5 { 6 phi[i]=i-1; 7 pr[++pc]=i; 8 } 9 for(int j=1;j<=pc&&i*pr[j]<=n;j++) 10 { 11 vis[i*pr[j]]=1; 12 if(i%pr[j]) 13 { 14 phi[i*pr[j]]=phi[i]*(pr[j]-1); 15 }else 16 { 17 phi[i*pr[j]]=phi[i]*pr[j]; 18 break; 19 } 20 } 21 }
2.约数个数 d(n)
n=(p1^a1)*(p2^a2)*...*(pk^ak)
则n的约数个数d(n)=(a1+1)*(a2+1)*...*(ak+1)。
对于某个质因数pi,某个约数要么包含少于ai个pi,要么不包含pi。
所以每对括号内,"1"表示如果不包含pi则只有一种选法(即不选pi)。
而ai表示如果选pi,有ai种选法(选1个、选2个、选3个......选ai个,共ai种选法)。
所以把每对括号乘到一起就是选法总数。每个选法都能乘出一个约数,所以选法总数就是约数个数。
这个式子其实有点类似母函数(生成函数)。
考虑怎么线性筛出来:
开一个辅助数组记录最小因子的幂次,即ai。
当i和pr[j]互质的时候,i的任意因数和pr[j]的任意因数相乘都能组成i*pr[j]的一个因数。
当i和pr[j]不互质的时候,我们算到i的时候,认为某个因子只有a个,而到i*pr[j]这个数的时候,有a+1个了。
所以我们把d[i]中的(a+1)除掉,再乘以(a+2)即可。
1 d[1]=1; 2 for(int i=2;i<=n;i++) 3 { 4 if(!vis[i]) 5 { 6 d[i]=2; 7 exp[i]=1; 8 pr[++pc]=i; 9 } 10 for(int j=1;j<=pc&&i*pr[j]<=n;j++) 11 { 12 vis[i*pr[j]]=1; 13 if(i%pr[j]) 14 { 15 d[i*pr[j]]=d[i]*d[pr[j]]; 16 exp[i*pr[j]]=1; 17 }else 18 { 19 d[i*pr[j]]=d[i]/(exp[i]+1)*(exp[i]+2); 20 exp[i*pr[j]]=exp[i]+1; 21 break; 22 } 23 } 24 }
3.约数和 σ(n)
σ(n)表示n的所有约数之和。
若把n分解为n=(p1^a1)*(p2^a2)*...*(pk^ak),
则σ(n)=(1+p1+p1^2+p1^3+...+p1^a1)*(1+p2+p2^2+p2^3+...+p2^a2)*...*(1+pk+pk^2+pk^3+...+pk^ak)。
这个式子的证明也很显然,跟约数个数的那个很像,也是类似母函数的想法,比较简单。
这个式子括号都拆开之后的每一项都是n的一个因数嘛,当然就是要加到一起喽。
线性筛出来稍稍有些麻烦。
代码中我用sig(sigma太长了,我看着别扭...)表示约数和。
开两个数组pw和spw辅助计算,pw相当于上式的pi^ai,即pi的最高次幂的值。
spw相当于(1+pi+pi^2+...+pi^ai)。
其它的想法就都跟约数个数差不多了。
1 sig[1]=1; 2 for(int i=2;i<=n;i++) 3 { 4 if(!vis[i]) 5 { 6 pw[i]=i; 7 spw[i]=i+1; 8 sig[i]=i+1; 9 pr[++pc]=i; 10 } 11 for(int j=1;j<=pc&&i*pr[j]<=n;j++) 12 { 13 vis[i*pr[j]]=1; 14 if(i%pr[j]) 15 { 16 pw[i*pr[j]]=pr[j]; 17 spw[i*pr[j]]=pr[j]+1; 18 sig[i*pr[j]]=sig[i]*sig[pr[j]]; 19 }else 20 { 21 pw[i*pr[j]]=pw[i]*pr[j]; 22 spw[i*pr[j]]=spw[i]+pw[i]*pr[j]; 23 sig[i*pr[j]]=sig[i]/spw[i]*spw[i*pr[j]]; 24 break; 25 } 26 } 27 }
4.莫比乌斯函数 μ(n)
这个基本上做莫比乌斯反演的时候用的很多......
然而pengzhou讲完了莫比乌斯反演之后我还没怎么做那个的题......
下面我用mu(n)表示莫比乌斯函数μ(n)。
莫比乌斯函数,mu(1)=1。
n存在平方因子时,mu(n)=0。
其余情况:即n=p1*p2*p3*...*pk(其中pi为质数)时,mu(n)=(-1)^k。
即当n不等于1、又没有平方因子时,根据n的质因子个数的奇偶性判断,是奇数则mu(n)为-1、是偶数则mu(n)为1。
线性筛的时候很简单,质数的mu为-1,遇到平方因子则为0。不是平方因子的,反转正负性即可。
1 mu[1]=1; 2 for(int i=2;i<=n;i++) 3 { 4 if(!vis[i]) 5 { 6 mu[i]=-1; 7 pr[++pc]=i; 8 } 9 for(int j=1;j<=pc&&i*pr[j]<=n;j++) 10 { 11 vis[i*pr[j]]=1; 12 if(i%pr[j]) 13 { 14 mu[i*pr[j]]=-mu[i]; 15 }else 16 { 17 mu[i*pr[j]]=0; 18 break; 19 } 20 } 21 }
最后放个四合一(虽然可能永远也用不到四合一):
1 phi[1]=d[1]=sig[1]=mu[1]=1; 2 for(int i=2;i<=n;i++) 3 { 4 if(!vis[i]) 5 { 6 phi[i]=i-1; 7 d[i]=2; 8 exp[i]=1; 9 pw[i]=i; 10 spw[i]=i+1; 11 sig[i]=i+1; 12 mu[i]=-1; 13 pr[++pc]=i; 14 } 15 for(int j=1;j<=pc&&i*pr[j]<=n;j++) 16 { 17 vis[i*pr[j]]=1; 18 if(i%pr[j]) 19 { 20 phi[i*pr[j]]=phi[i]*(pr[j]-1); 21 d[i*pr[j]]=d[i]*d[pr[j]]; 22 exp[i*pr[j]]=1; 23 pw[i*pr[j]]=pr[j]; 24 spw[i*pr[j]]=pr[j]+1; 25 sig[i*pr[j]]=sig[i]*sig[pr[j]]; 26 mu[i*pr[j]]=-mu[i]; 27 }else 28 { 29 phi[i*pr[j]]=phi[i]*pr[j]; 30 d[i*pr[j]]=d[i]/(exp[i]+1)*(exp[i]+2); 31 exp[i*pr[j]]=exp[i]+1; 32 pw[i*pr[j]]=pw[i]*pr[j]; 33 spw[i*pr[j]]=spw[i]+pw[i]*pr[j]; 34 sig[i*pr[j]]=sig[i]/spw[i]*spw[i*pr[j]]; 35 mu[i*pr[j]]=0; 36 break; 37 } 38 } 39 }