快速求一个积性函数 (f) 的前缀和,
记为 (S)
[S(n)=sum_{i=1}^{n} f(i)
]
考虑一个积性函数 (g)
[egin{aligned}
& sum_{i=1}^{n}(f*g)(i) \
=& sum_{i=1}^{n}sum_{d|n}^{i}f(d)g(frac{i}{n}) \
=& sum_{d=1}^ng(d)sum_{i=1}^{frac{n}{d}}f(i) \
=& sum_{d=1}^{n}g(d)S(frac{n}{d}) \
=& sum_{d=2}^ng(d)S(frac{n}{d})+g(1) imes S(n)
end{aligned}
]
所以我们得到了最重要的式子:
[g(1)S(n)=sum_{i=1}^{n}(f*g)(i)-sum_{d=2}^ng(d)S(frac{n}{d})
]
所以我们只要构造出一个 (g) ,我们能快速求出它的前缀和以及 (f * g) 的前缀和,那么对后面的整数分块, 复杂度 (O(n^{frac{3}{4}})) , 如果预处理到 (5e6), 复杂度近似为 (O(n^{frac{2}{3}}))。
伪代码:
ll GetSum(int n) { // 算 f 前缀和的函数
记忆化
ll ans = sum( (f * g)(n) ); // 算 f * g 的前缀和
// 以下这个 for 循环是数论分块
for(ll l = 2, r; l <= n; l = r + 1) { // 注意从 2 开始
r = (n / (n / l));
ans -= (g_sum(r) - g_sum(l - 1)) * GetSum(n / l); // g_sum 是 g 的前缀和 //递归 GetSum 求解
} return Sum(n) = ans;//记忆化
}
常用公式:
[mu * 1 = epsilon
]
[varphi * 1=Id
]
一个小小的拓展:
求 (sum_{i=1}^nvarphi(i) imes i)
首先来了解一个结论:
[(varphi imes Id) * Id=n^2
]
(手推一下)
这题就是求 (f=varphi imes Id) 的前缀和,
令 (g=Id)
[g(1)S(n)=sum_{i=1}^n(f*g)(i)-sum_{d=2}^ng imes S(frac{n}{d})
]
[(f*g)(n)=n^2
]
((f*g)(n)) 的前缀和为 (frac{n(n+1)(2n+1)}{6}).
然后就可以筛了。