[学习笔记] 欧拉线性筛与积性函数
[学习笔记] 欧拉线性筛与积性函数
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\);
- 若继续枚举更大的质数,生成的数就不会以当前质数作为最小质因子,会造成重复筛选。
因此:
时间复杂度为 \(O(n)\),空间复杂度为 \(O(n)\)。
2. 如何判断一个函数是不是积性函数
赛时主要记住定义和两个闭包性质。
2.1 定义
若算术函数 \(f\) 满足 \(f(1)=1\),并且对于任意 \(\gcd(a,b)=1\) 都有
则称 \(f\) 为积性函数。
若对于任意正整数 \(a,b\) 都有 \(f(ab)=f(a)f(b)\),则称 \(f\) 为完全积性函数。
积性只要求互质时成立;完全积性不要求互质。
2.2 积性函数的逐点乘积仍是积性函数
若 \(f,g\) 都是积性函数,定义逐点乘积
则当 \(\gcd(a,b)=1\) 时,
因此:
所以一个函数若能拆成若干个已知积性函数的逐点乘积,就可以直接判定它也是积性函数。
常见积性函数速查
| 函数 | 定义或质数幂取值 | 是否完全积性 |
|---|---|---|
| 常函数 \(\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 卷积:
若 \(f,g\) 都是积性函数,则 \(f*g\) 仍是积性函数。
常见关系:
- \(\mathbf 1*\mu=\varepsilon\),其中 \(\varepsilon(1)=1\),且 \(n>1\) 时 \(\varepsilon(n)=0\);
- \(\varphi*\mathbf 1=\operatorname{id}\),即 \(\displaystyle\sum_{d\mid n}\varphi(d)=n\);
- \(\mathbf 1*\mathbf 1=\tau\),即 \(\displaystyle\tau(n)=\sum_{d\mid n}1\);
- \(\operatorname{id}*\mathbf 1=\sigma\),即 \(\displaystyle\sigma(n)=\sum_{d\mid n}d\)。
赛时可以利用
快速判断函数是否具有积性。
2.4 复杂表达式判定为积性后:只研究 \(F(p^k)\)
很多题里的函数 \(F(n)\) 并不会直接给成常见积性函数,而是由若干已知积性函数通过逐点乘积或 Dirichlet 卷积组合得到。此时只要已经利用闭包性质判定出 \(F\) 是积性函数,就不必先求一般 \(n\) 上的完整通式。
若
由积性直接得到
因此:
复杂积性函数的核心不是先求出 \(F(n)\) 的完整通式,而是先求 \(F(p^k)\)。
求出质数幂上的取值后,既可以得到标准质因数分解形式,也可以直接研究
从而接入欧拉线性筛。
例:\(g(n)=\displaystyle\sum_{d\mid n}d\mu(d)\)
令
\(\operatorname{id}\) 与 \(\mu\) 都是积性函数,因此逐点乘积 \(h\) 是积性函数。又有
由 Dirichlet 卷积保持积性可知
此时不需要直接化简一般的 \(g(n)\),只计算质数幂:
由于
所以对任意 \(k\ge 1\),
于是当
时,由积性得到
这个函数只与 \(n\) 的不同质因子有关,与各质因子的指数无关。欧拉筛转移也随之得到:
当 \(p\nmid i\) 时:
当 \(p\mid i\) 时,因为 \(g(p{k+1})=g(pk)=1-p\),所以:
统一套路
遇到复杂函数时,优先按下面流程处理:
特别地,若 \(F=f*g\),则在质数幂上统一有
这通常比直接研究一般的 \(F(n)\) 简单得多。
3. 拿到一个积性函数,如何用欧拉筛线性预处理
在线性筛中枚举 \(x=i\cdot p\),只需讨论两种情况。
3.1 情况一:\(p\nmid i\)
此时 \(\gcd(i,p)=1\),直接利用积性:
3.2 情况二:\(p\mid i\)
由于质数从小到大枚举,并且遇到第一个满足 \(p\mid i\) 的质数后立即退出,因此此处的 \(p\) 是 \(i\) 的最小质因子。设
则
由积性可得
因此问题转化为研究
形式上可以写成
但代码中不能机械地做除法:\(f(p^k)\) 可能为 \(0\),模意义下也可能没有逆元。更稳妥的方法是维护质数幂块或根据具体公式直接递推。
3.3 通用推导流程
拿到一个新积性函数时,按下面四步处理:
- 先求出质数幂上的取值 \(f(p^k)\);
- 当 \(p\nmid i\) 时,直接使用 \(f(ip)=f(i)f(p)\);
- 当 \(p\mid i\) 时,令 \(i=p^km\),比较 \(f(p^k)\) 与 \(f(p^{k+1})\);
- 若递推需要知道 \(k\)、\(p^k\) 或 \(f(p^k)\),就在筛中增加相应辅助数组。
4. 常见积性函数的完整转移公式
4.1 欧拉函数 \(\varphi(n)\)
质数幂取值:
当 \(p\nmid i\) 时:
当 \(p\mid i\) 时,由 \(\varphi(p{k+1})=p\varphi(pk)\) 得:
4.2 莫比乌斯函数 \(\mu(n)\)
质数幂取值:
当 \(p\nmid i\) 时:
当 \(p\mid i\) 时,\(p^2\mid ip\),因此:
4.3 约数个数 \(\tau(n)\)
质数幂取值:
设 \(b[i]\) 表示 \(i\) 的最小质因子的指数。
当 \(p\nmid i\) 时:
当 \(p\mid i\) 时,设 \(i=p^km\),则
所以
代码中先除以 \(k+1\) 再乘 \(k+2\),这里一定整除。
4.4 约数和 \(\sigma(n)\)
质数幂取值:
维护:
- \(pw[i]=p^k\):\(i\) 的最小质因子的最高次幂;
- \(g[i]=1+p+\cdots+p^k\):最小质因子质数幂块的约数和。
当 \(p\nmid i\) 时:
当 \(p\mid i\) 时:
设 \(i=p^km\),则 \(\sigma(i)=\sigma(m)g[i]\),所以
代码中同样先除以 \(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. 赛时记忆版
只记下面四句话:
需要额外维护什么,取决于从 \(f(p^k)\) 递推到 \(f(p^{k+1})\) 时需要哪些信息。
这就是用欧拉线性筛处理积性函数的统一框架。

浙公网安备 33010602011771号