积性函数学习笔记
数论分块
对于形如
的式子,我们可以发现
code:
LL S(LL n) {
LL s = 0;
for (LL l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
s += (SumF(r) - SumF(l - 1)) * G(n / l);
}
return s;
}
扩展:
多维数论分块
如果式子形如
在取总块右边界的时候把
LL S(LL n) {
LL s = 0;
for (LL l = 1, r; l <= n; l = r + 1) {
r = INT64_MAX;
for (int i = 1; i <= k; ++i) {
r = min(r, a[i] / (a[i] / l));
}
s += (SumF(r) - SumF(l - 1)) * G(a[1] / l, a[2] / l, ..., a[k] / l);
}
return s;
}
多维嵌套数论分块
式子形如
直接递归,总块数量级为
LL S(LL n, int k) {
if (k == 0) {
return F(n);
}
LL s = 0;
for (LL l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
s += (SumG(r, k) - SumG(l - 1, k)) * S(n / l, k - 1);
}
return s;
}
积性函数
定义
如果一个数论函数
特别的,如果对于所有
性质
如果
常见积性函数
- 单位函数
,完全积性函数。 - 幂函数
, 一般简记为 ,完全积性函数。 - 常数函数
,也记作 ,完全积性函数。 - 因数个数函数
。 - 除数函数
, 时为因数和函数, 时为因数个数函数。 - 欧拉函数
。 - 莫比乌斯函数
,设 ,那么有 。
线性筛
我们在小学二年级就知道线性筛可以在
f[1] = 1;
for (int i = 2; i <= n; ++i) {
if (!v[i]) {
p.push_back(i), f[i] = /*f 在质数 i 处的取值*/;
sp[i] = i, bp[i] = i, kp[i] = 1;
}
for (int j : p) {
int k = i * j;
if (k > n) {
break;
}
v[k] = 1;
if (i % j) {
f[k] = f[i] * f[j];
sp[k] = j, bp[k] = j, kp[k] = 1;
} else {
if (sp[i] == i) {
f[k] = /*f 在质数的幂 bp[i]^(kp[i]+1)=k 处的取值*/;
} else {
f[k] = f[i / sp[i]] * f[j * sp[i]];
}
sp[k] = sp[i] * j, bp[k] = bp[i], kp[k] = kp[i] + 1;
break;
}
}
}
狄利克雷卷积
定义
对于两个数论函数
性质
- 满足交换律、结合律、分配律。
为狄利克雷卷积的单位元,即有 。 为狄利克雷卷积中 的逆元,即 。- 若
为积性函数,则 为积性函数。 。 。 , 。
狄利克雷(前/后)缀(和/差分)
我们经常会遇到求
以下讲解的是狄利克雷前缀和,等价于卷
它的本质是做多维前缀和,即对每个质数
模板题:P5495 Dirichlet 前缀和。
前缀和:
for (int i : p) {
for (int j = 1; i * j <= n; ++j) {
f[i * j] += f[j];
}
}
后缀和(实际上是做倍数卷积,即
for (int i : p) {
for (int j = n / i; j >= 1; --j) {
f[j] += f[i * j];
}
}
前缀差分:
for (int i : p) {
for (int j = n / i; j >= 1; --j) {
f[i * j] -= f[j];
}
}
后缀差分(实际上是做倍数卷积,即
for (int i : p) {
for (int j = 1; i * j <= n; ++j) {
f[j] -= f[i * j];
}
}
杜教筛
题目类型
求
算法解决
显然可以线性筛,时间复杂度
考虑构造积性函数
那么有:
把
于是我们只要能做到快速计算
以下是实现:
的前缀和
有
LL Sphi(int n) {
if (n < kM) {
return phi[n];
}
auto p = fphi.find(n);
if (p != fphi.end()) {
return p->second;
}
auto &f = fphi[n];
f = 1LL * n * (n + 1) / 2;
for (LL l = 2, r; l <= n; l = r + 1) {
r = n / (n / l);
f -= (r - l + 1) * Sphi(n / l);
}
return f;
}
的前缀和
有
LL Smu(int n) {
if (n < kM) {
return mu[n];
}
auto p = fmu.find(n);
if (p != fmu.end()) {
return p->second;
}
auto &f = fmu[n];
f = 1;
for (LL l = 2, r; l <= n; l = r + 1) {
r = n / (n / l);
f -= (r - l + 1) * Smu(n / l);
}
return f;
}
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
using LL = long long;
const int kM = 1664511;
int t, n;
LL phi[kM], mu[kM];
bool v[kM];
vector<LL> p;
unordered_map<LL, LL> fphi, fmu;
LL Sphi(LL n) {
if (n < kM) {
return phi[n];
}
auto p = fphi.find(n);
if (p != fphi.end()) {
return p->second;
}
auto &f = fphi[n];
f = n * (n + 1) / 2;
for (LL l = 2, r; l <= n; l = r + 1) {
r = n / (n / l);
f -= (r - l + 1) * Sphi(n / l);
}
return f;
}
LL Smu(LL n) {
if (n < kM) {
return mu[n];
}
auto p = fmu.find(n);
if (p != fmu.end()) {
return p->second;
}
auto &f = fmu[n];
f = 1;
for (LL l = 2, r; l <= n; l = r + 1) {
r = n / (n / l);
f -= (r - l + 1) * Smu(n / l);
}
return f;
}
int main() {
ios_base::sync_with_stdio(0), cin.tie(0);
phi[1] = mu[1] = 1;
for (LL i = 2; i < kM; ++i) {
if (!v[i]) {
phi[i] = i - 1, mu[i] = -1;
p.push_back(i);
}
for (LL j : p) {
if (i * j >= kM) {
break;
}
v[i * j] = 1;
if (i % j) {
phi[i * j] = phi[i] * phi[j], mu[i * j] = mu[i] * mu[j];
} else {
phi[i * j] = phi[i] * j, mu[i * j] = 0;
break;
}
}
}
for (LL i = 2; i < kM; ++i) {
phi[i] += phi[i - 1], mu[i] += mu[i - 1];
}
for (cin >> t; t--; ) {
cin >> n;
cout << Sphi(n) << ' ' << Smu(n) << '\n';
}
return 0;
}
莫比乌斯变换/反演
常见反演形式
形式一
更常见的形式是
形式二
如果有
(即
那么有
(即
形式三
如果有
那么有
常见反演套路
以下默认
形式一
设
可以手动分析
例题
PGCD - Primes in GCD Table
题意
求
思路
以下设
直接套上面的套路即可。
可以发现后面的东西可以线性筛,时间复杂度
多倍经验:P2257 YY的GCD,P2568 GCD。
GCDMAT - GCD OF MATRIX
题意
求
思路
以下设
设
直接套上面的式子得:
线性筛后数论分块即可,答案为
P1447 [NOI2010] 能量采集
题意
求
思路
显然有
直接套上面的式子即可。
P1390 公约数的和
题意
求
思路
直接套上面的式子即可。
LCMSUM - LCM Sum
题意
求
思路
发现后面那堆东西意义是与
注:注意特判
P3327 [SDOI2015]约数个数和
题意
求
思路
首先需要知道约数个数函数
证明:
对
:则对应的 的因子的对应项为 。 :设 的对应项为 ,则对应的 的因子的对应项为 。
容易发现这种表示方法不重。故得证。
以下设
由性质有
预处理
P5221 Product
题意
求
思路
原式即为
由于
分子部分
有
分母部分
有
看指数部分,有:
预处理
注意指数部分是对
P6055 [RC-02] GCD
题意
求
思路
有
杜教筛求
数论分块套杜教筛复杂度证明:
可以发现由于杜教筛内部是用数论分块实现的,所以只要筛一次
P3768 简单的数学题
题意
求
思路
有
设
设
注意到
关于如何发现上面那个式子。
首先直接设
我们知道
于是有
P3172 [CQOI2015]选数
题意
求
思路
设
杜教筛维护前缀和,数论分块即可。
P4449 于神之怒加强版
题意
求
对
思路
直接套式子得:
后面那坨东西做个狄利克雷前缀差分就好了。
P6825 「EZEC-4」求和
题意
求
对
思路
设
设
那么原式就是
直接暴力算即可,时间复杂度
P1829 [国家集训队]Crash的数字表格 / JZPTAB
题意
求
对
思路
以下设
设
看后面那部分
P6156 简单题
题意
求
对
思路
地狱绘图
设
于是有
设
设
:此时, 。 :此时, 。 :此时,对于 中的任意一项 ,都有 或 ,故 。
这时,我们就能用线性筛预处理
改一下可以过 P6222 「P6156 简单题」加强版。
P7486 「Stoi2031」彩虹
题意
求
对
思路
设
设
设
另一边,我们有:
代入原式,得:
设
再设
至此,我们可以通过数论分块解决问题。
整理一下要用的函数:
:位于指数上,可 计算,模 。 :位于底数上,可 预处理,模 。 :位于底数上,可 计算,模 。 :积性函数,位于指数上,可 预处理(线性筛),模 。 :位于底数上,可以 预处理,模 。 :位于底数上,可以 直接计算,模 。
再整理一下要预处理的东西:
:直接预处理 后前缀积。 :使用线性筛预处理, 。 :枚举 对倍数贡献即可。 的前缀和,对 取模。 的前缀积和逆元,对 取模。
P3704 [SDOI2017]数字表格
题意
求
对
思路
以下设
设
设
GCDMAT2 - GCD OF MATRIX (hard)
题意
求
对
思路
为方便,以下
这道题目我们在之前已经见过一次了,设
但是这样常数太大,过不去。考虑优化。
首先可以发现
设
但是这样常数还是太大,过不去。
优化一:考虑预处理
优化二:根号分治,设一个阈值
至此终于能过了。
P1587 [NOI2016] 循环之美
题意
求对于所有
思路
首先显然要满足
最后一步(
:显然令 即可。 :我们有 ,若 ,那么有 ,矛盾,故 。
此时式子就成了
求解这个式子即可。
我们有
设
这个式子是可以
那么有
现在这个式子已经可以数论分块了,现在只剩预处理
我们设
只看前面部分,有
于是有
这个式子也可以数论分块。采用类似杜教筛的方法即可。
总时间复杂度为
P3700 [CQOI2017]小 Q 的表格
题意
有一个表格
初始时
有
思路
首先有
这是辗转相减法的形式,结合
其中
于是我们只要维护
答案即为
设
设
于是有
原式即为
树状数组维护
P5518 [MtOI2019]幽灵乐团 / 莫比乌斯反演基础练习题
题意
求
其中
答案对
思路
原式显然等于
由于
答案即为
对于
预处理即可做到
对于
设
中间那部分显然可以
对于
其中
可以
对于
先看指数,有
代入原式,有
设
要预处理的东西和
直接考虑原式,设
再取
可以发现中间部分就是
P4240 毒瘤之神的考验
题意
求
对
思路
神仙题。
以下设
首先有一个经典结论:
证明:
我们有
(第二步由容斥原理可得)
因此有
设
设
那么原式就成了
发现这个式子不太好数论分块,考虑设
(可以看成是直接对
但是
考虑根号分治,设一个阈值
这时我们考虑
总时间复杂度为
P5572 [CmdOI2019]简单的数论题
题意
求
对
思路
以下设
我们有
由
设
那么有
再设
那么按 P4240 的套路做就行了。
注意预处理
总时间复杂度即为
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】