Loading

【学习笔记】狄利克雷前/后缀和/差分

Page Views Count

概述

定义约数求和为:

\[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)\) 的。

参考资料

posted @ 2023-08-11 15:22  SoyTony  阅读(248)  评论(7编辑  收藏  举报