数论函数小计
1.基础
数论函数
- 定义: 数论函数,就是值域为整数(陪域为复数)的函数
狄利克雷卷积
两个数论函数的狄利克雷卷积是一个新的函数
比如 , 它们的卷积就是
怎么卷呢?
定义:
举个例子:
狄利克雷卷积满足交换律和结合律:
=
=
基本函数
- 恒等函数: 无论n是什么,它永远等于
- 元函数: 只有时为1,其余为0 满足
- 编号函数:
完全积性函数
- 定义:对于完全积性函数 有任意整数使
函数都是完全积性函数
积性函数
- 定义:对于积性函数 若 则
完全积性函数是积性函数
后面的 和都是积性函数
性质:
- 对于任意积性函数 有
因为 所以 若这个积性函数无意义
- 两个积性函数的卷积还是积性函数
- 积性函数的逆元也是积性函数
:满足时 和互逆
2.莫比乌斯函数
如果我们知道 可以通过 (是恒等函数) 求出F
那如果我们知道 怎么求 ? 两边同时乘上就行
就是莫比乌斯函数
根据是积性函数 所以也是积性函数
那么怎么算?
首先
从素数开始考虑 设当前素数为
根据 还是素数
所以
所以
所以
然后再想素数的多次方
把带入
同理可得
根据积性函数的性质,容易得到的定义:
- 得 当含有平方因子
- 得 为的质因子个数
莫比乌斯反演
怎么反演呢?
当有这样的问题:
这样就能转化了
为什么?这其实就是卷积呗 只有卷才能为
例题
链接 here
现在有这样的问题:
带入反演
往前提
再化简
这样就是的
整除分块一下就是的
具体实现
线性筛
线性筛可以做到处理出以内的
特别地,如果单独求一个,可以用枚举因数的做法
怎么线性筛呢?分类讨论
- 在时 说明和已经出现了重复因子 只需令
- 否则 可以根据积性函数的性质转移即可
code
void init()
{
p[1]=1;
mul[1]=1;
for(int i=2;i<=MAXN-3;i++)
{
if(!p[i])
{
q[++l]=i;
mul[i]=-1;
}
for(int j=1;j<=l&&i*q[j]<=MAXN-3;j++)
if(i%q[j]==0)
{
p[i*q[j]]=1;
mul[i*q[j]]=0;
break;
}
else
{
p[i*q[j]]=1;
mul[i*q[j]]=mul[i]*mul[q[j]];
}
}
}
整除分块
观察公式
发现一定存在一段是连续的
这段重复算会浪费很多时间
把这些相同的分成一块块 加上前缀和一起算可以优化成的
每次一块一块枚举即可
这些芝士结合一下就是例题的解
code
#include<bits/stdc++.h>
#define ll long long
#define MAXN 50005
using namespace std;
int g,mul[MAXN],p[MAXN];
int q[MAXN],l;
ll n,m,d,ans;
void init()
{
p[1]=1;
mul[1]=1;
for(int i=2;i<=MAXN-3;i++)
{
if(!p[i])
{
q[++l]=i;
mul[i]=-1;
}
for(int j=1;j<=l&&i*q[j]<=MAXN-3;j++)
if(i%q[j]==0)
{
p[i*q[j]]=1;
mul[i*q[j]]=0;
break;
}
else
{
p[i*q[j]]=1;
mul[i*q[j]]=mul[i]*mul[q[j]];
}
}
for(int i=2;i<=MAXN-3;i++)
mul[i]+=mul[i-1];
}
void solve()
{
for(int l=1,r=0;l<=min(n,m);l=r+1)
{
r=min(n/(n/l),m/(m/l));
ans+=(n/l)*(m/l)*(mul[r]-mul[l-1]);
}
}
int main()
{
init();
scanf("%d",&g);
while(g--)
{
ans=0;
scanf("%lld%lld%lld",&n,&m,&d);
n/=d,m/=d;
solve();
printf("%lld\n",ans);
}
return 0;
}
例题2
链接:here
这道题题目让我们求是质数的个数
首先 将题目转化成
前提得
如果此时直接按这个做时间复杂度为
过不了 当柿子无法优化时可以用另一个方法
然后发现后面这$\sum\limits_{k\in prime ,k|T}\mu(T/k) O(nloglogn)$埃氏筛预处理
前面能整除优化
因此 时间复杂度降至 能通过本题
Code
#include<bits/stdc++.h>
#define ll long long
#define MAXN 10000005
using namespace std;
int n,g,m;
int q[MAXN],l;
int p[MAXN],mul[MAXN],sum[MAXN];
ll ans;
void init()
{
mul[1]=p[1]=1;
for(int i=2;i<=MAXN-3;i++)
{
if(!p[i])
{
mul[i]=-1;
q[++l]=i;
}
for(int j=1;j<=l&&q[j]*i<=MAXN-3;j++)
{
p[q[j]*i]=1;
if(i%q[j]==0)
{
mul[q[j]*i]=0;
break;
}
else mul[q[j]*i]=mul[q[j]]*mul[i];
}
}
for(int i=1;i<=l;i++)
for(int j=1;j*q[i]<=MAXN-3;j++)
sum[j*q[i]]+=mul[j];
for(int i=2;i<=MAXN-3;i++)
sum[i]+=sum[i-1];
}
ll solve(int n,int m)
{
ll s=0;
for(int l=1,r=0;l<=min(n,m);l=r+1)
{
r=min(n/(n/l),m/(m/l));
s+=1ll*(n/l)*(m/l)*(sum[r]-sum[l-1]);
}
return s;
}
int main()
{
init();
scanf("%d",&g);
while(g--)
{
scanf("%d%d",&n,&m);
printf("%lld\n",solve(n,m));
}
return 0;
}
3 欧拉函数
定义表示中与互质的数的个数
推导 借助容斥
则
上面左边的那一坨根据观察可以化简为
借助这个东西我们可以通过的时间复杂度分解质因数得出
可是如果要求这些咋办?
其实是积性函数 证明
则
然后自行取百度吧后面我看不懂
最终得
口胡结束
其实也可以感性理解一下
根据互质 可知 和有的所有质因子
因此
二次口胡结束
好了你已经知道是积性函数了 现在你只需要使用线性筛就可以了
怎么筛呢 还是分类
-
当筛的时候 时 说明和中已经相同质因子 所以已经包含所有质因子 因此 这个证明拆公式就行
-
否则 直接使用积性函数的性质即可
Code
void init()
{
phi[1]=p[1]=1;
for(int i=2;i<=n;i++)
{
if(!p[i])
{
phi[i]=i-1;
q[++l]=i;
}
for(int j=1;j<=l&&q[j]*i<=n;j++)
{
p[q[j]*i]=1;
if(i%q[j]==0)
{
phi[q[j]*i]=phi[i]*q[j];
break;
}
else phi[q[j]*i]=phi[q[j]]*phi[i];
}
}
}
例题
链接:here
题目让我们求
枚举d
d的枚举提前
优化
转化
定睛一看 不就吗 直接优化原柿
转化
发现后面的柿子可以前缀和优化 然后前面跑一遍可以过了本题
Code
#include<bits/stdc++.h>
#define ll long long
#define MAXN 100005
using namespace std;
int n;
int q[MAXN],l;
int p[MAXN],phi[MAXN];
ll ans,sum[MAXN];
void init()
{
phi[1]=p[1]=1;
for(int i=2;i<=n;i++)
{
if(!p[i])
{
phi[i]=i-1;
q[++l]=i;
}
for(int j=1;j<=l&&q[j]*i<=n;j++)
{
p[q[j]*i]=1;
if(i%q[j]==0)
{
phi[q[j]*i]=phi[i]*q[j];
break;
}
else phi[q[j]*i]=phi[q[j]]*phi[i];
}
}
for(int i=1;i<=n;i++)
sum[i]=phi[i]+sum[i-1];
}
int main()
{
scanf("%d",&n);
init();
for(int i=1;i<=n;i++)
ans+=i*(2*sum[n/i]-1);
printf("%lld",ans);
return 0;
}
欧拉反演
首先要知道一条理论:
证明:
我们把分成
其中 约分后分母相同为一类
同分母的数的个数为
举个例子
那么分母为的数很明显是与互质的 就是
分母为的数很明显是 去掉一个因数与互质的数个数
那么其实可以转化成 与互质的数个数 为
,同理 原柿得证
这种方法叫做映射法
根据这个性质可以得到:
我们又知道
所以
例题
还是
但是有了组数据 我们如果直接搞肯定T
根据我们学习的欧拉反演 我们可以变换原柿
前提d
然后发现柿子与无关 可以优化为
合并
然后整除分块可以优化成
Code
#include<bits/stdc++.h>
#define ll long long
#define MAXN 100005
using namespace std;
int n;
int q[MAXN],l;
int p[MAXN],phi[MAXN];
ll ans,sum[MAXN];
void init()
{
phi[1]=p[1]=1;
for(int i=2;i<=n;i++)
{
if(!p[i])
{
phi[i]=i-1;
q[++l]=i;
}
for(int j=1;j<=l&&q[j]*i<=n;j++)
{
p[q[j]*i]=1;
if(i%q[j]==0)
{
phi[q[j]*i]=phi[i]*q[j];
break;
}
else phi[q[j]*i]=phi[q[j]]*phi[i];
}
}
for(int i=1;i<=n;i++)
sum[i]=phi[i]+sum[i-1];
}
ll solve(int n)
{
ll s=0;
for(int l=1,r;l<=n;l=r+1)
{
r=n/(n/l);
s+=1ll*(n/l)*(n/l)*(sum[r]-sum[l-1]);
}
return s;
}
int main()
{
scanf("%d",&n);
init();
printf("%lld",solve(n));
return 0;
}
练习题:here
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】