狄利克雷前/后缀和
简介
考虑解决如下问题:
\[n = 1 \sim N,
f(n) = \sum_{d \mid n} g(d),
f^\prime(d) = \sum_{d \mid n} g(n)
\]
这个问题就是狄利克雷前/后缀和,也就是求 \(f = g * 1,f^\prime * 1 = g\)。
分析
朴素计算的复杂度是调和级数级别 \(\mathcal O(n \ln n)\),但我们希望得到近似线性的做法。
首先考虑狄利克雷求和累计的特点,对于一个 \(d\),设它能贡献到的集合为 \(S_d = \{n:d \mid n\}\),显然,若 \(d^\prime \mid d\),有 \(S_{d^\prime} \subset S_d\)。
显然,这又大量重复的贡献,考虑着手优化。我们发现每个质因子是独立的,我们考虑将每一个质因子的次数设为一个维度,那么这件事就等价于求高维前缀和,复杂度 \(\mathcal O(n\log\log n)\)。
for (int i = 1; i <= tot; i++)
for (int j = 1; j * pr[i] <= n; j++)
f[j * pr[i]] += f[j];
考虑高维后缀和类似,至于要倒过来做就行了:
for (int i = 1; i <= tot; i++)
for (int j = n / pr[i]; j; j--)
f[j] += f[j * pr[i]];
狄利克雷差分
其实相当于逆推狄利克雷前缀和,把两个循环都反过来枚举就行了:
for (int i = tot; i; i--)
for (int j = n / pr[i]; j; j--)
f[j * pr[i]] -= f[j];
for (int i = tot; i; i--)
for (int j = 1; j * pr[i] <= n; j++)
f[j] -= f[j * pr[i]];

浙公网安备 33010602011771号