【学习笔记】狄利克雷前/后缀和/差分
概述
定义约数求和为:
\[f(n)=\sum_{d\mid n}g(d)
\]
也就是 \(f=g*\mathrm{I}\),容易反演得到:
\[g(n)=\sum_{d\mid n}\mu\left(\dfrac{n}{d}\right)f(d)
\]
称上面形式为约数差分,即约数求和的逆运算。
定义倍数求和为:
\[f(n)=\sum_{n\mid d}g(d)
\]
容易发现约数求和等价于 \(f=Ag\),其中 \(A\) 是矩阵,\(f,g\) 均为列向量。注意到 \(A_{i,j}=[j\mid i]\),而倍数求和对应出 \(f=Bg\),\(B_{i,j}=[i\mid j]\),也就是 \(B=A^{T}\)。
矩阵转置的逆等于矩阵逆的转置,因此 \(A^{-1}_{i,j}=\mu\left(\frac{i}{j}\right)[j\mid i]\),可以推得 \(B^{-1}_{i,j}=\mu\left(\frac{j}{i}\right)[i\mid j]\),因此:
\[g(n)=\sum_{n\mid d}\mu\left(\dfrac{d}{n}\right)f(d)
\]
称上面形式为倍数差分,即倍数求和的逆运算。
如何 \(O(n\log \log n)\) 计算
类似高维前缀和,把每个质数 \(p\) 设为一维,狄利克雷前缀和即求约数求和:
for(int i=1;i<=pr[0];++i){
for(int j=1;j<=lim/pr[i];++j){
a[j*pr[i]]+=a[j];
}
}
同理狄利克雷后缀和即求倍数求和:
for(int i=1;i<=pr[0];++i){
for(int j=lim/pr[i];j>=1;--j){
a[j]+=a[j*pr[i]];
}
}
之后狄利克雷前缀差分即求约数差分,本质是逆运算,和 \(\mu\) 无关:
for(int i=1;i<=pr[0];++i){
for(int j=lim/pr[i];j>=1;--j){
a[j*pr[i]]-=a[j];
}
}
同理狄利克雷后缀差分即求倍数差分:
for(int i=1;i<=pr[0];++i){
for(int j=1;j<=lim/pr[i];++j){
a[j]-=a[j*pr[i]];
}
}
差分和求和的第二维枚举顺序显然相反,求和的枚举顺序可以轻松手动得到。
复杂度分析类似埃式筛,质数位置的倒数求和是 \(O(n\log \log n)\) 的。