常见数论函数求法
一. 莫比乌斯函数
定义:$\mu(n) = \begin{cases} 1, & \text{if $n$ = 1} \\ (-1)^k, & \text{if $n = p_1*p_2*...*p_k$ } \\0, & \text{其它} \end{cases}$
单点求法: 根据定义的$O(\sqrt{n})$求法如下
int Mu(int n) { int ret = 1, mx = sqrt(n+0.5); for (int i=2; i<=mx; ++i) if (n%i==0) { n /= i, ret = -ret; if (n%i==0) return 0; } return n>1?-ret:ret; }
根据$\mu$的积性可以用欧筛在$O(n)$时间预处理出前$n$项.
const int N = 1e6+10; int phi[N], mu[N], p[N], cnt, vis[N]; void init() { mu[1] = 1; for (int i=2; i<N; ++i) { if (!vis[i]) p[++cnt]=i,mu[i]=-1; for (int j=1,t; j<=cnt&&i*p[j]<N; ++j) { vis[t=i*p[j]] = 1; if (i%p[j]==0) {mu[t]=0;break;} mu[t]=-mu[i]; } } }
根据$\sum\limits_{d|n}\mu(d)=[n=1]$可以得到$O(nlogn)$预处理前$n$项的算法.
for (int i=mu[1]=1; i<=n; ++i) { for (int j=2*i; j<=n; j+=i) mu[j]-=mu[i]; }
二. 欧拉函数
定义: $\varphi(n)$为不超过$n$且与$n$互质的正整数个数.
利用容斥原理可以得到$\varphi(n)=n\prod\limits_{p|n} \frac{p-1}{p}$, 可以得到单点求法:
int Phi(int n) { int ret = n, mx = sqrt(n+0.5); for (int i=2; i<=mx; ++i) if (n%i==0) { ret = ret/i*(i-1); while (n%i==0) n/=i; } return n>1?ret/n*(n-1):ret; }
$O(nloglogn)$求法
for (int i=1; i<N; ++i) phi[i] = i; for (int i=2; i<N; ++i) if(phi[i]==i) { for(int j=i, t=i-1; j<N; j+=i) { phi[j] = phi[j]/i*t; } }
根据$\varphi$的积性同样可以用欧筛在$O(n)$时间预处理出前$n$项.
const int N = 1e6+10; int phi[N], mu[N], p[N], cnt, vis[N]; void init() { phi[1] = 1; for (int i=2; i<N; ++i) { if (!vis[i]) p[++cnt]=i,phi[i]=i-1; for (int j=1,t; j<=cnt&&i*p[j]<N; ++j) { vis[t=i*p[j]] = 1; if (i%p[j]==0) {phi[t]=phi[i]*p[j];break;} phi[t]=phi[i]*phi[p[j]]; } } }