数论学习笔记(二):数论函数
数论函数
基本概念
数论函数:定义域为正整数的函数。
加性函数:若对于任意正整数
若对于任意正整数
积性函数、完全积性函数:见数论学习笔记(一):同余相关
可以发现,对于积性函数
唯一分解定理:任何大于
常见数论函数
设正整数
-
单位函数:
,显然,它是完全积性函数。 -
常量函数:
,也很显然,它是完全积性函数。 -
幂函数:
,当 时记为 ,此时它被称作恒等函数,它是完全积性函数。
证:对于正整数
- 除数函数:
,当 时记为 或 ,此时它表示 的因子个数;当 时记为 ,此时它表示 的因数和,他是积性函数。
证:对于正整数
当
计算式:
证:当
当
-
欧拉函数:
,它表示小于等于 且与 互质的数的个数,它的基本性质详见数论学习笔记(一):同余相关 -
本质不同的质因子个数函数:
,它表示一个数本质不同的质因子个数(有点废话),他是加性函数
证:对于正整数
当
当
考虑容斥原理,则有:
- 莫比乌斯函数:
它是积性函数。
证:当
当
当
其他情况中
- 总质因数个数函数:
,它表示一个数质数幂因子的个数,它是完全加性函数。
证:首先,当
- 刘维尔函数:
,显然,它是完全积性函数。
狄利克雷卷积
定义
两个数论函数
性质
- 交换律:
。
证:
考虑到
- 结合律:
。
证:
- 分配律:
。
证:
- 单位元:
。
证:
现在我们可以发现,
- 积性函数
存在狄利克雷逆当且仅当 。
证:设
假设
- 积性函数的狄利克雷逆仍是积性函数。
证:考虑数学归纳法。
设
对于
根据上一条推出的递推式,
由于此时
后方的式子
- 两个积性函数的狄利克雷卷积仍是积性函数。
证:设
数论函数之间的关系
证:
证:我们已经在数论学习笔记(一):同余相关中用一个比较取巧的方法证明了这个式子,现在我们再用狄利克雷卷积来证明。
因为
证:由于我们知道了
证:
证:
点积
整除分块
这是数论题最常见的做法。组合数推式子一般推到所有因子可以预处理,而数论推式子一般就推到所有因子可以求前缀和或可以整除分块。
考虑一共有多少个不同的
-
若
,则不同的 只有 种,于是不同的 也只有 种。 -
若
,则 ,因此 也只有 种。
于是我们就可以很容易求出这
for(int l = 1, r; l <= n; l = r + 1)
r = n / (n / l);
于是对于每个
莫比乌斯反演
首先,莫比乌斯反演是一类特殊的子集反演,详见组合数学学习笔记(二):鸽巢原理、容斥及反演。莫比乌斯反演式子如下:
证:
现在可以发现,由于
将莫比乌斯反演与子集反演的式子进行对比:
不难发现二者有一些相似之处:考虑记
解:非常经典的莫比乌斯反演的题目,我们要求
首先我们先改变枚举方式,先枚举最大公约数
考虑到若
现在可以发现
考虑到
由于
完整代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 4e6 + 9;
int vis[N], prime[N], phi[N], sum[N], n, ans;
void get_phi(){
phi[1] = 1;
int cnt = 0;
for(int i = 2; i < N; i++){
if(!vis[i]){
vis[i] = i;
prime[cnt++] = i;
phi[i] = i - 1;
}
for(int j = 0; j < cnt && i * prime[j] < N; j++){
vis[i * prime[j]] = prime[j];
if(i % prime[j] == 0){
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
phi[i * prime[j]] = phi[i] * phi[prime[j]];
}
}
for(int i = 1; i < N; i++)
sum[i] = sum[i - 1] + phi[i];
}
signed main(){
get_phi();
scanf("%lld", &n);
for(int l = 1, r; l <= n; l = r + 1){
r = n / (n / l);
ans += (n / l) * (n / l) * (sum[r] - sum[l - 1]);
}
printf("%lld", ans);
return 0;
}
与上一道题一样,只是这次要求的式子变成了
注意最后这道题要
完整代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 4e6 + 9;
int vis[N], prime[N], phi[N], sum[N], n, m, ans;
void get_phi(){
phi[1] = 1;
int cnt = 0;
for(int i = 2; i < N; i++){
if(!vis[i]){
vis[i] = i;
prime[cnt++] = i;
phi[i] = i - 1;
}
for(int j = 0; j < cnt && i * prime[j] < N; j++){
vis[i * prime[j]] = prime[j];
if(i % prime[j] == 0){
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
phi[i * prime[j]] = phi[i] * phi[prime[j]];
}
}
for(int i = 1; i < N; i++)
sum[i] = sum[i - 1] + phi[i];
}
signed main(){
get_phi();
scanf("%lld%lld", &n, &m);
for(int l = 1, r; l <= n && l <= m; l = r + 1){
r = min(n / (n / l), m / (m / l));
ans += (n / l) * (m / l) * (sum[r] - sum[l - 1]);
}
printf("%lld", ans * 2 - n * m);
return 0;
}
这道题要求
还是大力推式子:
依然先求出
完整代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 4e5 + 9;
int vis[N], prime[N], mu[N], sum[N], ans;
void get_mu(){
mu[1] = 1;
int cnt = 0;
for(int i = 2; i < N; i++){
if(!vis[i]){
vis[i] = i;
prime[cnt++] = i;
mu[i] = -1;
}
for(int j = 0; j < cnt && i * prime[j] < N; j++){
vis[i * prime[j]] = prime[j];
if(i % prime[j] == 0)
break;
mu[i * prime[j]] = -mu[i];
}
}
for(int i = 1; i < N; i++)
sum[i] = sum[i - 1] + mu[i];
}
int main(){
get_mu();
int n;
scanf("%d", &n);
n--;
if(!n){
printf("0\n");
return 0;
}
for(int l = 1, r; l <= n; l = r + 1){
r = n / (n / l);
ans += (n / l) * (n / l) * (sum[r] - sum[l - 1]);
}
printf("%d", ans + 2);
return 0;
}
这题变成求
依然枚举最大公因数
记
现在若能预处理积性函数
我们将
设
完整代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e7 + 9, MOD = 20101009;
int vis[N], prime[N], sum[N], f[N], ans, n, m;
void get_f(){
f[1] = 1;
int cnt = 0;
for(int i = 2; i < N; i++){
if(!vis[i]){
vis[i] = i;
prime[cnt++] = i;
f[i] = 1 - i + MOD;
}
for(int j = 0; j < cnt && i * prime[j] < N; j++){
vis[i * prime[j]] = prime[j];
if(i % prime[j] == 0){
f[i * prime[j]] = f[i];
break;
}
f[i * prime[j]] = f[i] * f[prime[j]] % MOD;
}
}
for(int i = 1; i < N; i++)
sum[i] = (sum[i - 1] + i * f[i] % MOD) % MOD;
}
signed main(){
get_f();
scanf("%lld%lld", &n, &m);
if(n > m)
swap(n, m);
for(int l = 1, r; l <= n && l <= m; l = r + 1){
r = min(n / (n / l), m / (m / l));
ans = (ans + ((n / l) * (n / l + 1) / 2 % MOD) * ((m / l) * (m / l + 1) / 2 % MOD) % MOD * (sum[r] - sum[l - 1]) % MOD + MOD) % MOD;
}
printf("%lld", ans);
return 0;
}
这真的是基础练习题吗?
线性筛积性函数与应用
高级筛法
这两个算法都可以快速求积性函数的前缀和。
杜教筛
对于一个积性函数
我们再找到一个积性函数
交换求和顺序,先枚举
由于
我们令
具体地,由于不同的
考虑到
以洛谷的杜教筛模板为例。
我们来试着筛出
注意到
对于函数
法1
法二
注意到
完整代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e6 + 9;
int prime[N], mu[N], phi[N], sum1[N], sum2[N];
bool vis[N];
unordered_map <int, int> summu, sumphi;
void init(){
int cnt = 0;
vis[0] = vis[1] = 1;
mu[1] = phi[1] = 1;
for(int i = 2; i < N; i++){
if(!vis[i]){
prime[cnt++] = i;
mu[i] = -1;
phi[i] = i - 1;
}
for(int j = 0; j < cnt && i * prime[j] < N; j++){
vis[i * prime[j]] = 1;
if(i % prime[j]){
mu[i * prime[j]] = -mu[i];
phi[i * prime[j]] = phi[i] * phi[prime[j]];
} else {
mu[i * prime[j]] = 0;
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
}
}
for(int i = 1; i < N; i++){
sum1[i] = sum1[i - 1] + mu[i];
sum2[i] = sum2[i - 1] + phi[i];
}
}
int getsmu(int x){
if(x < N)
return sum1[x];
if(summu[x])
return summu[x];
int ans = 1;
for(int l = 2, r; l <= x; l = r + 1){
r = x / (x / l);
ans -= (r - l + 1) * getsmu(x / l);
}
return summu[x] = ans;
}
int getphi(int x){
if(x < N)
return sum2[x];
if(sumphi[x])
return sumphi[x];
int ans = x * (x + 1) / 2;
for(int l = 2, r; l <= x; l = r + 1){
r = x / (x / l);
ans -= (r - l + 1) * getphi(x / l);
}
return sumphi[x] = ans;
}
signed main(){
init();
int t;
scanf("%lld", &t);
while(t--){
int n;
scanf("%lld", &n);
printf("%lld %lld\n", getphi(n), getsmu(n));
}
return 0;
}
Powerful Number
对于正整数
- 所有的
都可以写成 的形式;
证:若
以内的 有 个。
证:考虑先枚举
正题
参考资料
-
王hx、黄yy、张hr 的课件
-
初等数论学习笔记 III:数论函数与筛法 Alex_wei
-
【数学】加性函数与积性函数 mangoworld
-
杜教筛(+贝尔级数+powerful number) command_block
-
炫酷反演魔术 command_block
本文来自博客园,作者:JPGOJCZX,转载请注明原文链接:https://www.cnblogs.com/JPGOJCZX/p/18422868
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!