除数函数求和

· · 个人记录

除数函数求和

Description

除数函数定义为 \sigma_k(n) = \sum_{d \mid n} d^k,求 \sum_{i = 1}^n \sigma_k(i) \mod 1000000007

## Solution 不妨计算每个数对答案的贡献。具体的,对于 $x$,那么 $x$ 的倍数都会在计算除数函数时计算到 $x$,那么我们可以求出 $x$ 实际的贡献($x^k$)和 $x$ 贡献的次数(也就是 $x$ 的倍数个数 $\lfloor \frac nx \rfloor$)。所以第 $x$ 个数对答案的贡献即 $x^k \times \left \lfloor \dfrac nx \right \rfloor$。 直接快速幂计算 $x^k$ 是会超时的,所以考虑预处理求出所有 $x \in [1, n]$ 的 $x^k$ 的值。 可以注意到,若将 $x$ 质因数分解为 $\alpha_1^{\beta_1}\alpha_2^{\beta_2}\cdots\alpha_t^{\beta_t}$(其中 $\alpha_1, \alpha_2, \dots. \alpha_t$ 为质数),那么很显然有: $$ x^k = \left(\alpha_1^{\beta_1}\right)^k\left(\alpha_2^{\beta_2}\right)^k\cdots \left(\alpha_t^{\beta_t}\right)^k $$ 首此启发,我们可以暴力(指复杂度为 $\log n$ 的快速幂)求出每个质数的 $k$ 次方的值,然后将每个数的质因子的答案相乘即可。 显然这一步可以在欧拉筛的过程中计算。定义 $v_i = i^k$。枚举时,若 $i$ 为质数,则直接快速幂计算 $v_i$。否则枚举质数 $p_j$,那么 $v_{p_j \cdot i}$ 的显然为 $v_{p_j}\cdot v_i$。然后就能预处理出所有 $x \in [1, n]$ 的 $x^k$ 的值了。 ## Code ~~~cpp #include <iostream> using namespace std; typedef long long LL; const int N = 1e7 + 10, P = 1e9 + 7; int n, k, res; int p[N], v[N], cnt; bool st[N]; int fpm(int a, int b) { int res = 1; while (b) { if (b & 1) res = (LL)res * a % P; b >>= 1, a = (LL)a * a % P; } return res; } int main() { cin >> n >> k; v[1] = 1; for (int i = 2; i <= n; ++ i ) { if (!st[i]) p[ ++ cnt] = i, v[i] = fpm(i, k); for (int j = 1; p[j] <= n / i; ++ j ) { st[p[j] * i] = true; v[p[j] * i] = (LL)v[p[j]] * v[i] % P; if (i % p[j] == 0) break; } } for (int i = 1; i <= n; ++ i ) res = (res + (LL)n / i * v[i]) % P; cout << res; return 0; } ~~~