积性函数&莫比乌斯反演&筛法
符号约定
P 表示质数集合
在不加说明的情况下,p 为某个质数,pi 表示从小到大第 i 个质数,且 p0=1
minp(x) 表示 x 的最小质因子
数论函数
定义在正整数域上的函数,值域在正整数域上的函数称为数论函数
狄利克雷卷积
对于两个数论函数 f,g 定义其狄利克雷卷积为 (f∗g)(n)=∑d∣nf(d)g(dn)
狄利克雷卷积有如下性质
-
交换律: f∗g=g∗f
-
结合律: f∗(g∗h)=(f∗g)∗h
-
分配律: f∗(g+h)=f∗g+f∗h
-
有单位元 ϵ
-
若 f,g 均为积性函数,则 f∗g 也为积性函数
证明下性质5
(f∗g)(ij)=d∣ij∑f(d)g(dij),i⊥j(f∗g)(ij)=d1∣i∑d2∣j∑f(d1d2)g(d1d2ij)=d1∣i∑d2∣j∑f(d1)f(d2)g(d1i)g(d2j)=(d1∣i∑f(d1)g(d1i))(d2∣j∑f(d2)g(d2j))=(f∗g)(i)(f∗g)(j)
积性函数
若一个数论函数 f 满足 f(1)=1 and ∀gcd(i,j)=1→f(ij)=f(i)f(j) ,我们则称它是积性函数
特别的,对于满足 ∀i,j,f(i∗j)=f(i)∗f(j) 的数论函数 f ,我们称它是完全积性函数
常见的积性函数
元函数: ϵ(n)=[n=1]
恒等函数: I(n)=1
单位函数: id(n)=n
幂函数: idk(n)=nk
约数个数函数:d(n) 或 σ0(n)
约数和函数:σ(n)
除数函数: σk(n)
欧拉函数: φ(n)
莫比乌斯函数: μ(n)=⎩⎪⎨⎪⎧1,n=1(−1)k,n为k个不同质数之积0,n有平方因子
积性函数的筛法
我们可以利用欧拉筛在线性时间内筛出任意积性函数 f
对于欧拉筛我们只需讨论两种情况
- i⊥p,p is prime,f(ip)=f(i)(p)
- i=pkj,j⊥p,p is prime,f(ip)=f(j)f(pk+1)
对于不同的数论函数具体讨论即能求出
小结论
-
μ∗I=ϵ
记n有k个不同素因子
(μ∗I)(n)=∑d∣nμ(d)=∑i=0k(−1)k(ik)=(1−1)k=[k=0]=[n=1]
-
φ∗I=id
即 ∑d∣nφ(d)=n
这个的证明考虑分母为n的n个真分数,约分后分子分母互质且每一个分母 d 出现次数为 φ(d)
考虑每一个分母为 d 的,分子与 d 互质的 φ(d) 个分数大小不一且唯一
同时乘上 dn 后,分子一一对应[1,n]
-
μ∗id=φ
考虑结论2与结论1
μ∗id=μ∗φ∗I=(μ∗I)∗φ=ϵ∗φ=φ
莫比乌斯反演
根据我们已经学会的结论,我们能轻松得到莫比乌斯反演的公式了
f∗I=g⟺g∗μ=f
由结论1可证
g(n)=∑d∣nf(d)⟺f(n)=∑d∣nμ(d)g(dn)
通过结论1,我们也有
∑d∣nμ(d)=[n=1]
经典式子推导
默认 n≤m
复杂度记号 O(T1)−O(T2) 表示预处理 O(T1) 单次询问 O(T2)
-
∑i=1n∑j=1m[gcd(i,j)=1]
套路莫反一波
∑i=1n∑j=1m∑d∣gcd(i,j)μ(d)
考虑直接枚举 gcd(i,j) 的因数 d
∑d=1n∑i=1dn∑j=1dmμ(d)∑d=1nμ(d)⌊dn⌋⌊dm⌋
通过欧拉筛预处理 μ 和整除分块可以做到 O(n)−O(n)
-
∑i=1n∑j=1mgcd(i,j)
套路枚举 gcd
∑d=1nd∑i=1dn∑j=1dm[gcd(i,j)=1]
右边是我们熟悉的问题1,转化为
∑d=1nd∑g=1dnμ(g)⌊dgn⌋⌊dgm⌋
直接计算这个式子复杂度是 O(∑d=1ndn)=O(n)
考虑枚举 t=dg 交换一波和式
∑t=1n⌊tn⌋⌊tm⌋∑d∣tdμ(dt)
不难发现第二重和式就是 (μ∗id)(t)=φ(t)
简化为
∑t=1n⌊tn⌋⌊tm⌋φ(t)
通过欧拉筛预处理 φ 和整除分块同样可以做到 O(n)−O(n)
-
∑i=1n∑j=1m[gcd(i,j)=1]ij
类似问题1
先套路莫反
∑i=1n∑j=1m∑d∣gcd(i,j)μ(d)ij=∑d=1nd2μ(d)∑i=1dn∑j=1dmij=∑d=1nd2μ(d)4(⌊dn⌋+1)⌊dn⌋(⌊dm⌋+1)⌊dm⌋
预处理 id2μ ,整除分块可以做到 O(n)−O(n)
-
∑i=1n∑j=1mlcm(i,j)
由于 lcm 并没有 gcd 那么优美的性质,我们一般将其转化为 gcd 计算
∑i=1n∑j=1mgcd(i,j)ij=∑d=1nd1∑i=1dn∑j=1dm[gcd(i,j)=1]idjd=∑d=1nd∑i=1dn∑j=1dm[gcd(i,j)=1]ij
第二三重和式为问题3
简化为
∑d=1nd∑g=1dng2μ(g)4(⌊dgn⌋+1)⌊dgn⌋(⌊dgm⌋+1)⌊dgm⌋
由于这个部分式子不够优美,不能像问题2那样凑出一个优美的狄利克雷卷积
我们直接整除分块套两次处理这个问题
记 f(n,m)=∑d=1nd2μ(d)4(⌊dn⌋+1)⌊dn⌋(⌊dm⌋+1)⌊dm⌋
ans=∑d=1ndf(⌊dn⌋,⌊dm⌋)
时间复杂度 O(??) 不太会算复杂度,如果记忆化后大概比线性略优
-
d(ij)=∑x∣i∑y∣i[gcd(x,y)=1]
约数个数的经典转化
这里放出Siyuan大佬的证明
-
∑i=1n∑j=1md(ij)
运用问题5的结论,交换和式得
∑d=1nμ(d)∑x=1dn∑y=1dm⌊xdn⌋⌊ydm⌋
可以做到 O(n)−O(n)
筛法
开始简单科技了
快速求得 ∑i=1nf(i),f 为某个数论函数
由于各种毒瘤出题人的存在,我们的式子可能已经难以更进一步了,达到了线性的优异复杂度
很多时候,式子的瓶颈均在线性筛上(毕竟这玩意是线性的),我们需要更优的方法筛出某个积性函数
更高深的奇怪筛法大多能在比线性略低的复杂度做到这一点
杜教筛
杜教筛的原理很简单,考虑一个性质优异的积性函数 g 与 f 卷一起的前缀和
∑i=1n(f∗g)(i)=∑i=1n∑d∣ig(d)f(di)=∑d=1ng(d)∑i=1⌊dn⌋f(i)
我们敏锐的观察到后面的式子是 f 的前 ⌊dn⌋ 项和
考虑把 d=1 的一项提出来,∑i=1n(f∗g)(i)=g(1)∑i=1nf(i)+∑d=2ng(d)∑i=1⌊dn⌋f(i)
∑i=1nf(i)=∑d=2ng(d)∑i=1⌊dn⌋f(i)−∑i=1n(f∗g)(i)
只要 g 的性质足够优越,使得 f∗g,g 的前缀和均能快速求得且前面一项可通过整除分块降低复杂度
我们便成功的达到了我们的目的——降低复杂度
若 (f∗g)(n) 的前缀和计算复杂度为 T0(n), ∑i=1nf(i) 的计算复杂度为 T1(n)
由于我们共需运算 n 个 f 的前缀和,算上整除分块的复杂度与 n 个取值,枚举取值 i
则 T1(n)=∑i=1nO(i)+O(in)=O(n43)
我们还能再优化一点,考虑线性筛筛出 f 前 M 的取值
复杂度 T1(n)=∑i=1⌊Mn⌋O(in)=O(Mn)+O(M)
M=n32 时复杂度最优
复杂度分析不懂.jpg
经典例子
-
∑i=1nφ(i)
直接考虑 φ∗1=id
显然我们容易求 id,1 的前缀和
-
∑i=1nμ(i)
考虑 μ∗1=ϵ
1,ϵ 的前缀和不要太弱智
-
∑i=1nφ(i)ik
考虑 (φ⋅idk)∗idk=idk+1
((φ⋅idk)∗idk)(n)=∑d∣nφ(d)dk(dn)k=nk∑d∣nφ(d)=nk+1
idk 的前缀和可以插值,或斯特林数,伯努利数等方法求出
Min_25筛
相比与杜教筛的使用条件,Min_25更为通用
Min_25筛能处理所有在f(p)处取值为关于p的低阶多项式且f(pc)能快速求值的数论函数前缀和问题
求∑i=1nf(i),设m=n内质数个数
思路
由于 f(p) 是关于 p 的低阶多项式,我们只需求多项式每一项相加即可
首先,我们试图求出
Gk(n)=∑i=1n[i∈P]ik
由于Gk(n) 并不好求,我们考虑通过dpF(i,n) 得到 Gk(n)
Fk(i,n)=∑x=1n[x∈P or minp(x)>pi]xk
显然,Fk(m,n)=Gk(n)
同时,Fk(0,n)=Sk(n)=∑x=1nxk,上自然数幂之和可得,dp过程暂不展开
接下来考虑设计一个dp计算答案
S(i,n)=∑x=2nf(x)[minp(x)>pi]
注意没有计算 f(1)
考虑最终答案显然为 S(0,n)
显然我们知道S(m,n)=0
求解S(i,x) 的过程中会用到 Gk(x) 的信息
Part 1
Fk(i,n)→Fk(i+1,n)
我们仅需考虑去掉 {x∣minp(x)=pi+1} 的贡献
记x=y∗pi+1,minp(y)>pi
Fk(i+1,n)=Fk(i,n)−(Fk(i,⌊pi+1n⌋)−Gk(pi))pi+1k
考虑减去所有y的贡献
Fk(i,⌊pi+1n⌋) 但多算了这里面的质数部分,即Gk(pi)
由于i≤m,考虑线性筛预处理一部分 Gk(pi) 即可
Part 2
S(i+1,n)→S(i,n)
我们直接暴力枚举 pi+1e 的指数 e
S(i,n)=S(i+1,n)+∑e=1f(pi+1e)(S(i+1,⌊pi+1en⌋)+1)
具体实现时我们考虑用Part 1中的 Gk 计算∑j=i+1f(pj)
我们得以计算 minp(x)≥pm 的部分
具体实现
由于我们需要存储许多关于 ⌊in⌋ 的信息
我们可以利用我们熟知的整除分块中这类数的性质,只有 2n 种取值,离散化即可
考虑将值域在 n 内的部分用 ind1 查出离散化后的编号
值域大于 n 的部分将 ⌊in⌋ 存入 ind2 以便查询
以洛谷模板给出代码
【模板】Min_25筛
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxsn=1e5+5,mod=1e9+7;
int iv2,iv3;
ll n,m;
int tot;
ll val[2*maxsn];
int ind1[maxsn],ind2[maxsn];
int f1[2*maxsn],f2[2*maxsn];
ll read(){
ll x=0,y=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*y;
}
inline int add(int x){
if(x>=mod)x-=mod;
return x;
}
inline int sub(int x){
if(x<0)x+=mod;
return x;
}
inline int power(int x,int b){
int ans=1;
while(b){
if(b&1)ans=1ll*ans*x%mod;
x=1ll*x*x%mod;
b>>=1;
}
return ans;
}
bool bj[maxsn];
int len;
int p[maxsn];
int id[maxsn],id2[maxsn];
void pre(){
m=sqrt(n);
for(int i=2;i<=m;i++){
if(!bj[i]){
p[++len]=i;
id[len]=add(id[len-1]+i);
id2[len]=add(id2[len-1]+1ll*i*i%mod);
}
for(int j=1;1ll*i*p[j]<=m&&j<=len;j++){
bj[i*p[j]]=1;
if(i%p[j]==0)break;
}
}
return ;
}
int S(int i,ll x){
if(p[i]>=x)return 0;
int k=(x<=m?ind1[x]:ind2[n/x]);
int ans=sub(sub(f2[k]-f1[k])-sub(id2[i]-id[i]));
for(int j=i+1;j<=len&&1ll*p[j]*p[j]<=x;j++){
ll pr=p[j];
for(int e=1;pr<=x;e++,pr=pr*p[j]){
int v=pr%mod;
ans=add(ans+1ll*v*(v-1)%mod*(S(j,x/pr)+(e!=1))%mod);
}
}
return ans;
}
int main(){
n=read();
iv2=power(2,mod-2);iv3=power(3,mod-2);
pre();
for(ll l=1,r=0;l<=n;l=r+1){
ll v=n/l;
r=n/v;
val[++tot]=v;
if(v<=m)ind1[v]=tot;
else ind2[n/v]=tot;
v=v%mod;
f1[tot]=1ll*v*(v+1)%mod*iv2%mod;f1[tot]--;
f2[tot]=1ll*v*(v+1)%mod*(2ll*v%mod+1)%mod*iv2%mod*iv3%mod;f2[tot]--;
}
for(int i=1;i<=len;i++){
for(int j=1;1ll*p[i]*p[i]<=val[j]&&j<=tot;j++){
int k=(val[j]/p[i]<=m?ind1[val[j]/p[i]]:ind2[n/(val[j]/p[i])]);
f1[j]=sub(f1[j]-1ll*sub(f1[k]-id[i-1])*p[i]%mod);
f2[j]=sub(f2[j]-1ll*sub(f2[k]-id2[i-1])*p[i]%mod*p[i]%mod);
}
}
printf("%d\n",add(S(0,n)+1));
return 0;
}