杜教筛
1 积性函数和狄利克雷卷积
1.1 积性函数
1.1.1 定义
积性函数在以前的学习中遇到过很多,例如莫比乌斯函数
- 称定义域在正整数上的函数叫做数论函数(也叫算数函数)。
- 对于一个数论函数
,如果 对于任意互质的 都成立,则称 为积性函数。 - 特别的,对于一个数论函数
,如果 对于任意的 都成立,则称 为完全积性函数。
1.1.2 常见积性函数
- 单位函数:
(完全积性)。 - 恒等函数:
(完全积性)。其中 ,通常简记为 。 - 常数函数:
(完全积性)。 - 除数函数:
。其中 即因子个数,通常简记为 ; 即因子之和,通常简记为 。 - 欧拉函数:
。 - 莫比乌斯函数:
。
1.2 狄利克雷卷积
1.2.1 定义
对于两个数论函数
上式通常简记为:
例如在
。 。 。 。
1.2.2 性质
- 交换律:
。 - 结合律:
。 - 分配率:
。
2 杜教筛
2.1 引入
首先需要了解的前置知识:积性函数、狄利克雷卷积、数论分块。
杜教筛处理的是对于一类数论函数
2.2 算法思想
对于一个数论函数
于是会有如下递推式:
假如我们可以构造适当的函数
- 可以快速求解出
。 - 可以快速求解出
的前缀和,以便后面使用数论分块求解 。
我们就能在较短时间内求得
具体来讲,杜教筛的时间复杂度是 map
等数据结构存储下
2.3 例题
例 1:【模板】杜教筛。
题意:求
先考虑求
根据狄利克雷卷积可知,
然后考虑求
关于欧拉函数有一个广为人知的性质:
,即 。通过这个也就可以证明出上文提到的 的结论了。
我们仍然构造
代码如下:
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#define int long long
using namespace __gnu_pbds;
using namespace std;
const int Maxn = 2e6 + 5;
const int Inf = 2e9;
int T;
int n;
int prim[Maxn], cnt, mu[Maxn], phi[Maxn];
bool vis[Maxn];
const int N = 2e6;
void init() {
mu[1] = 1;
phi[1] = 1;
for(int i = 2; i <= N; i++) {
if(!vis[i]) {
prim[++cnt] = i;
mu[i] = -1;
phi[i] = i - 1;
}
for(int j = 1, x; j <= cnt && (x = prim[j] * i) <= N; j++) {
vis[x] = 1;
if(i % prim[j] == 0) {
mu[x] = 0;
phi[x] = phi[i] * prim[j];
break;
}
mu[x] = -mu[i];
phi[x] = phi[i] * (prim[j] - 1);
}
}
for(int i = 1; i <= N; i++) {
mu[i] += mu[i - 1];
phi[i] += phi[i - 1];
}
}
gp_hash_table <int, int> smu, sphi;
int sum_mu(int x) {
if(x <= N) return mu[x];
if(smu[x]) return smu[x];
int l = 2, r = 0, res = 1;
while(l <= x) {
r = x / (x / l);
res -= sum_mu(x / l) * (r - l + 1);
l = r + 1;
}
return smu[x] = res;
}
int sum_phi(int x) {
if(x <= N) return phi[x];
if(sphi[x]) return sphi[x];
int l = 2, r = 0, res = (x + 1) * x / 2;
while(l <= x) {
r = x / (x / l);
res -= sum_phi(x / l) * (r - l + 1);
l = r + 1;
}
return sphi[x] = res;
}
void solve() {
cin >> n;
cout << sum_phi(n) << " " << sum_mu(n) << '\n';
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> T;
init();
while(T--) solve();
return 0;
}
例 2:[CQOI2015] 选数。
题意: 求出在值域区间
这是经典
根据莫比乌斯反演可得:
根据定义,我们又知道
但是发现这个式子无法通过数论分块去优化复杂度,因此需要另辟蹊径。考虑在原始的
令
此时整个式子就可以数论分块求解了,但是此时发现线性求
例 3: [BZOJ3512] DZY Loves Math IV
题意: 求
观察到一个很重要的点,
考虑设
此时我们考虑标准分解式,令
不难发现此时
发现这个式子是一个递归的形式,我们采用类似杜教筛的形式求解这个式子即可。当然还注意递归边界,当
考虑一下它的时间复杂度,在
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律