一些重要的数论函数+线性筛模板

数论这块其实有好多函数,挺让人头疼的。

本篇主要讲解一些数论函数(欧拉函数、约数个数、约数和、莫比乌斯函数)以及它们的线性筛求法。

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 }
原文地址:https://www.cnblogs.com/cervusy/p/9885357.html