[学习笔记] 欧拉线性筛与积性函数

[学习笔记] 欧拉线性筛与积性函数

TAG: 数论, 欧拉线性筛, 积性函数, 欧拉函数, 莫比乌斯函数

1. 欧拉线性筛原理

每个合数 \(x\) 只由 \(x/\operatorname{mpf}(x)\) 乘上它的最小质因子 \(\operatorname{mpf}(x)\) 生成一次,因此总复杂度为 \(O(n)\)。

标准写法:

for(int i=2;i<=n;i++){
    if(!mpf[i]){
        pri.push_back(i);
        mpf[i]=i;
    }
    for(int p:pri){
        if(p>n/i) break;
        mpf[i*p]=p;
        if(i%p==0) break;
    }
}

为什么 i%p==0 后必须 break

  • pri 按从小到大的顺序枚举;
  • 枚举到第一个满足 \(p\mid i\) 的质数时,\(p\) 就是 \(i\) 的最小质因子;
  • 此时 \(ip\) 的最小质因子也是 \(p\);
  • 若继续枚举更大的质数,生成的数就不会以当前质数作为最小质因子,会造成重复筛选。

因此:

\[\boxed{\text{每个合数恰好被自己的最小质因子筛到一次}} \]

时间复杂度为 \(O(n)\),空间复杂度为 \(O(n)\)。


2. 如何判断一个函数是不是积性函数

赛时主要记住定义和两个闭包性质。

2.1 定义

若算术函数 \(f\) 满足 \(f(1)=1\),并且对于任意 \(\gcd(a,b)=1\) 都有

\[\boxed{f(ab)=f(a)f(b)}, \]

则称 \(f\) 为积性函数。

若对于任意正整数 \(a,b\) 都有 \(f(ab)=f(a)f(b)\),则称 \(f\) 为完全积性函数。

积性只要求互质时成立;完全积性不要求互质。

2.2 积性函数的逐点乘积仍是积性函数

若 \(f,g\) 都是积性函数,定义逐点乘积

\[h(n)=f(n)g(n), \]

则当 \(\gcd(a,b)=1\) 时,

\[\begin{aligned} h(ab) &=f(ab)g(ab)\\ &=f(a)f(b)g(a)g(b)\\ &=h(a)h(b). \end{aligned} \]

因此:

\[\boxed{f,g\text{ 积性}\Longrightarrow fg\text{ 积性}} \]

所以一个函数若能拆成若干个已知积性函数的逐点乘积,就可以直接判定它也是积性函数。

常见积性函数速查

函数 定义或质数幂取值 是否完全积性
常函数 \(\mathbf 1(n)\) \(\mathbf 1(n)=1\)
恒等函数 \(\operatorname{id}(n)\) \(\operatorname{id}(n)=n\)
幂函数 \(\operatorname{id}_k(n)\) \(\operatorname{id}_k(n)=n^k\)
莫比乌斯函数 \(\mu(n)\) \(\mu(p)=-1,\ \mu(p^k)=0\ (k\ge 2)\)
欧拉函数 \(\varphi(n)\) \(\varphi(pk)=p(p-1)\)
约数个数 \(\tau(n)\) \(\tau(p^k)=k+1\)
约数和 \(\sigma(n)\) \(\sigma(pk)=1+p+\cdots+pk\)
广义约数和 \(\sigma_t(n)\) \(\sigma_t(pa)=1+pt+\cdots+p^{at}\)
Jordan 函数 \(J_t(n)\) \(J_t(pa)=p-p^{(a-1)t}\)
Liouville 函数 \(\lambda(n)\) \(\lambda(n)=(-1)^{\Omega(n)}\)

例如,\(\varphi(n)\mu(n)\)、\(n^k\mu(n)\)、\(\varphi(n)\tau(n)\) 都是积性函数。

这里的“乘积”指逐点乘积 \((fg)(n)=f(n)g(n)\),不是 Dirichlet 卷积。

2.3 Dirichlet 卷积保持积性

定义 Dirichlet 卷积:

\[\boxed{(f*g)(n)=\sum_{d\mid n}f(d)g\left(\frac nd\right)} \]

若 \(f,g\) 都是积性函数,则 \(f*g\) 仍是积性函数。

常见关系:

  1. \(\mathbf 1*\mu=\varepsilon\),其中 \(\varepsilon(1)=1\),且 \(n>1\) 时 \(\varepsilon(n)=0\);
  2. \(\varphi*\mathbf 1=\operatorname{id}\),即 \(\displaystyle\sum_{d\mid n}\varphi(d)=n\);
  3. \(\mathbf 1*\mathbf 1=\tau\),即 \(\displaystyle\tau(n)=\sum_{d\mid n}1\);
  4. \(\operatorname{id}*\mathbf 1=\sigma\),即 \(\displaystyle\sigma(n)=\sum_{d\mid n}d\)。

赛时可以利用

\[\boxed{\text{已知积性函数}\xrightarrow{\text{逐点乘积或 Dirichlet 卷积}}\text{新的积性函数}} \]

快速判断函数是否具有积性。

2.4 复杂表达式判定为积性后:只研究 \(F(p^k)\)

很多题里的函数 \(F(n)\) 并不会直接给成常见积性函数,而是由若干已知积性函数通过逐点乘积或 Dirichlet 卷积组合得到。此时只要已经利用闭包性质判定出 \(F\) 是积性函数,就不必先求一般 \(n\) 上的完整通式。

\[n=\prod_{i=1}^r p_i^{a_i}, \]

由积性直接得到

\[\boxed{F(n)=\prod_{i=1}^rF(p_i^{a_i})}. \]

因此:

复杂积性函数的核心不是先求出 \(F(n)\) 的完整通式,而是先求 \(F(p^k)\)。

求出质数幂上的取值后,既可以得到标准质因数分解形式,也可以直接研究

\[F(p^k)\longrightarrow F(p^{k+1}), \]

从而接入欧拉线性筛。

例:\(g(n)=\displaystyle\sum_{d\mid n}d\mu(d)\)

\[h(n)=n\mu(n)=\operatorname{id}(n)\mu(n). \]

\(\operatorname{id}\) 与 \(\mu\) 都是积性函数,因此逐点乘积 \(h\) 是积性函数。又有

\[g=h*\mathbf 1, \]

由 Dirichlet 卷积保持积性可知

\[\boxed{g\text{ 是积性函数}}. \]

此时不需要直接化简一般的 \(g(n)\),只计算质数幂:

\[g(p^k) =\sum_{d\mid p^k}d\mu(d) =\sum_{j=0}^{k}p^j\mu(p^j). \]

由于

\[\mu(1)=1,\qquad \mu(p)=-1,\qquad \mu(p^j)=0\quad(j\ge 2), \]

所以对任意 \(k\ge 1\),

\[\boxed{g(p^k)=1-p}. \]

于是当

\[n=\prod_{i=1}^r p_i^{a_i} \]

时,由积性得到

\[\boxed{g(n)=\prod_{i=1}^r(1-p_i)=\prod_{p\mid n}(1-p)}. \]

这个函数只与 \(n\) 的不同质因子有关,与各质因子的指数无关。欧拉筛转移也随之得到:

\[g(p)=1-p. \]

当 \(p\nmid i\) 时:

\[\boxed{g(ip)=g(i)(1-p)}. \]

当 \(p\mid i\) 时,因为 \(g(p{k+1})=g(pk)=1-p\),所以:

\[\boxed{g(ip)=g(i)}. \]

统一套路

遇到复杂函数时,优先按下面流程处理:

\[\boxed{ \begin{gathered} \text{拆成已知积性函数} \longrightarrow \text{利用逐点乘积或卷积闭包判定积性}\\ \longrightarrow \text{计算 }F(p^k) \longrightarrow F(n)=\prod_iF(p_i^{a_i})\\ \longrightarrow \text{研究 }F(p^k)\to F(p^{k+1}) \longrightarrow \text{欧拉筛} \end{gathered}} \]

特别地,若 \(F=f*g\),则在质数幂上统一有

\[\boxed{F(p^k)=\sum_{j=0}^{k}f(p^j)g(p^{k-j})}. \]

这通常比直接研究一般的 \(F(n)\) 简单得多。


3. 拿到一个积性函数,如何用欧拉筛线性预处理

在线性筛中枚举 \(x=i\cdot p\),只需讨论两种情况。

3.1 情况一:\(p\nmid i\)

此时 \(\gcd(i,p)=1\),直接利用积性:

\[\boxed{f(ip)=f(i)f(p)} \]

3.2 情况二:\(p\mid i\)

由于质数从小到大枚举,并且遇到第一个满足 \(p\mid i\) 的质数后立即退出,因此此处的 \(p\) 是 \(i\) 的最小质因子。设

\[i=p^km,\qquad \gcd(p,m)=1, \]

\[ip=p^{k+1}m. \]

由积性可得

\[f(i)=f(p^k)f(m),\qquad f(ip)=f(p^{k+1})f(m). \]

因此问题转化为研究

\[\boxed{f(p^k)\longrightarrow f(p^{k+1})}. \]

形式上可以写成

\[f(ip)=f(i)\frac{f(p^{k+1})}{f(p^k)}, \]

但代码中不能机械地做除法:\(f(p^k)\) 可能为 \(0\),模意义下也可能没有逆元。更稳妥的方法是维护质数幂块或根据具体公式直接递推。

3.3 通用推导流程

拿到一个新积性函数时,按下面四步处理:

  1. 先求出质数幂上的取值 \(f(p^k)\);
  2. 当 \(p\nmid i\) 时,直接使用 \(f(ip)=f(i)f(p)\);
  3. 当 \(p\mid i\) 时,令 \(i=p^km\),比较 \(f(p^k)\) 与 \(f(p^{k+1})\);
  4. 若递推需要知道 \(k\)、\(p^k\) 或 \(f(p^k)\),就在筛中增加相应辅助数组。

4. 常见积性函数的完整转移公式

4.1 欧拉函数 \(\varphi(n)\)

质数幂取值:

\[\boxed{\varphi(p^k)=p^{k-1}(p-1)} \]

当 \(p\nmid i\) 时:

\[\boxed{\varphi(ip)=\varphi(i)(p-1)} \]

当 \(p\mid i\) 时,由 \(\varphi(p{k+1})=p\varphi(pk)\) 得:

\[\boxed{\varphi(ip)=p\varphi(i)} \]

4.2 莫比乌斯函数 \(\mu(n)\)

质数幂取值:

\[\mu(p)=-1,\qquad \boxed{\mu(p^k)=0\quad(k\ge 2)} \]

当 \(p\nmid i\) 时:

\[\boxed{\mu(ip)=-\mu(i)} \]

当 \(p\mid i\) 时,\(p^2\mid ip\),因此:

\[\boxed{\mu(ip)=0} \]

4.3 约数个数 \(\tau(n)\)

质数幂取值:

\[\boxed{\tau(p^k)=k+1} \]

设 \(b[i]\) 表示 \(i\) 的最小质因子的指数。

当 \(p\nmid i\) 时:

\[\boxed{\tau(ip)=2\tau(i)},\qquad b[ip]=1. \]

当 \(p\mid i\) 时,设 \(i=p^km\),则

\[\tau(i)=(k+1)\tau(m),\qquad \tau(ip)=(k+2)\tau(m), \]

所以

\[\boxed{\tau(ip)=\frac{\tau(i)}{k+1}(k+2)},\qquad b[ip]=b[i]+1. \]

代码中先除以 \(k+1\) 再乘 \(k+2\),这里一定整除。

4.4 约数和 \(\sigma(n)\)

质数幂取值:

\[\boxed{\sigma(p^k)=1+p+p^2+\cdots+p^k} \]

维护:

  • \(pw[i]=p^k\):\(i\) 的最小质因子的最高次幂;
  • \(g[i]=1+p+\cdots+p^k\):最小质因子质数幂块的约数和。

当 \(p\nmid i\) 时:

\[pw[ip]=p,\qquad g[ip]=1+p, \]

\[\boxed{\sigma(ip)=\sigma(i)(1+p)}. \]

当 \(p\mid i\) 时:

\[pw[ip]=pw[i]\cdot p,\qquad g[ip]=g[i]+pw[ip]. \]

设 \(i=p^km\),则 \(\sigma(i)=\sigma(m)g[i]\),所以

\[\boxed{\sigma(ip)=\frac{\sigma(i)}{g[i]}g[ip]}. \]

代码中同样先除以 \(g[i]\),该除法在整数意义下一定整除。


5. 常见函数质数幂速查

函数 \(f(p^k)\)
\(\varphi(n)\) \(p^{k-1}(p-1)\)
\(\mu(n)\) \(-1\ (k=1),\ 0\ (k\ge 2)\)
\(\tau(n)\) \(k+1\)
\(\sigma(n)\) \(1+p+\cdots+p^k\)
\(n^t\) \(p^{kt}\)
\(J_t(n)\) \(p{kt}-p\)

6. 完整线性筛代码

下面的代码同时预处理:

  • 最小质因子 mpf
  • 欧拉函数 phi
  • 莫比乌斯函数 mu
  • 约数个数 d
  • 约数和 sig

辅助数组含义:

  • b[i]:\(i\) 的最小质因子的指数;
  • pw[i]:\(i\) 的最小质因子的最高次幂;
  • g[i]:\(i\) 的最小质因子质数幂块的约数和。
完整代码(点击展开)
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
vector<int> pri;
vector<int> mpf,phi,mu;
vector<int> b,d;
vector<int> pw,g,sig;
void sieve(int n){
    pri.clear();
    mpf.assign(n+1,0);
    phi.assign(n+1,0);
    mu.assign(n+1,0);
    b.assign(n+1,0);
    d.assign(n+1,0);
    pw.assign(n+1,0);
    g.assign(n+1,0);
    sig.assign(n+1,0);
    mpf[1]=phi[1]=mu[1]=1;
    d[1]=pw[1]=g[1]=sig[1]=1;
    for(int i=2;i<=n;i++){
        if(mpf[i]==0){
            pri.push_back(i);
            mpf[i]=i;
            phi[i]=i-1;
            mu[i]=-1;
            b[i]=1;
            d[i]=2;
            pw[i]=i;
            g[i]=sig[i]=1+i;
        }
        for(int p:pri){
            if(p>n/i) break;
            int x=i*p;
            mpf[x]=p;
            if(i%p==0){
                phi[x]=phi[i]*p;
                mu[x]=0;
                b[x]=b[i]+1;
                d[x]=d[i]/(b[i]+1)*(b[i]+2);
                pw[x]=pw[i]*p;
                g[x]=g[i]+pw[x];
                sig[x]=sig[i]/g[i]*g[x];
                break;
            }else{
                phi[x]=phi[i]*(p-1);
                mu[x]=-mu[i];
                b[x]=1;
                d[x]=d[i]*2;
                pw[x]=p;
                g[x]=1+p;
                sig[x]=sig[i]*(1+p);
            }
        }
    }
}
void solve(){
    int n;cin>>n;
    sieve(n);
    // 调用后可直接使用 mpf[x]、phi[x]、mu[x]、d[x]、sig[x]
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t=1;
    while(t--) solve();
    return 0;
}

若题目要求取模,不能直接照搬 d[i]/...sig[i]/...;应维护去掉最小质因子幂块后的部分,或在模数为质数且分母可逆时使用逆元。


7. 赛时记忆版

只记下面四句话:

\[\boxed{\text{欧拉筛:每个合数只由自己的最小质因子生成一次}} \]

\[\boxed{n=p^km,\ \gcd(p,m)=1\Longrightarrow f(n)=f(p^k)f(m)} \]

\[\boxed{p\nmid i\Longrightarrow f(ip)=f(i)f(p)} \]

\[\boxed{p\mid i\Longrightarrow\text{研究 }f(p^k)\to f(p^{k+1})} \]

需要额外维护什么,取决于从 \(f(p^k)\) 递推到 \(f(p^{k+1})\) 时需要哪些信息。

这就是用欧拉线性筛处理积性函数的统一框架。

posted @ 2026-08-16 14:52  艾拉别哭  阅读(3)  评论(0)    收藏  举报