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

发布时间 2023-08-11 15:26:46作者: SoyTony

简述

定义约数求和为:

\[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(\dfrac{i}{j}\right)[j\mid i]\),可以推得 \(B^{-1}_{i,j}=\mu\left(\dfrac{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]];
    }
}