题目链接:Project Euler 745

定义 $g(n)$ 表示最大的能够整除 $n$ 的完全平方数。例如 $g(18) = 9, g(19) = 1$。

定义 $S(n) = \sum_{i = 1}^{n} g(i)$,求 $S(10^{14}) \bmod (10^{9} + 7)$


Solution

设 $g(x) = i^{2}$,由于 $\frac{x}{i^{2}}$ 不能含有平方因子,可以枚举 $i$ 并枚举 $\frac{x}{i^{2}}$ 的值,得到:

$$ \sum_{i = 1}^{\lfloor\sqrt{n}\rfloor} i^{2} \sum_{j = 1}^{\left\lfloor\frac{n}{i^{2}}\right\rfloor} \mu^{2}(j) $$

后面的 $\sum$ 本质上是 $1 \sim \left\lfloor\frac{n}{i^{2}}\right\rfloor$ 中没有平方因子的数字个数,设其为 $h\left(\left\lfloor\frac{n}{i^{2}}\right\rfloor\right)$,可以容斥求 $h(n)$:

$$ \begin{align*} h(n) = n - \sum_{i} \left\lfloor\frac{n}{p_{i}^{2}}\right\rfloor + \sum_{i < j} \left\lfloor\frac{n}{(p_{i} p_{j})^{2}}\right\rfloor - \ldots \end{align*} $$

设 $(p_{i_{1}} p_{i_{2}} p_{i_{3}} \ldots p_{i_{k}})^{2} = x^2$,则 $\left\lfloor\frac{n}{x^{2}}\right\rfloor$ 项的系数为 $(-1)^{k}$ 且 $x$ 满足无平方因子,式子改写为:

$$ h(n) = \sum_{i = 1}^{\lfloor\sqrt{n}\rfloor} \left\lfloor\frac{n}{i^{2}}\right\rfloor \mu(i) $$

代入原式:

$$ \begin{align*} & \sum_{i = 1}^{\lfloor\sqrt{n}\rfloor} i^{2} h\left(\left\lfloor\frac{n}{i^{2}}\right\rfloor\right) \\ = & \sum_{i = 1}^{\lfloor\sqrt{n}\rfloor} i^{2} \sum_{j = 1}^{\left\lfloor\sqrt{\frac{n}{i^{2}}}\right\rfloor} \left\lfloor\frac{n}{(ij)^{2}}\right\rfloor \mu(j) \\ = & \sum_{p = 1}^{\lfloor\sqrt{n}\rfloor} \left\lfloor\frac{n}{p^{2}}\right\rfloor \sum_{i \mid p} \mu(i) \left(\frac{p}{i}\right)^{2} \end{align*} $$

注意到后面的 $\sum$ 是一个积性函数,记为 $f(p)$,则有:

$$ \begin{align*} f(n) & = \sum_{i \mid n} \mu(i) \left(\frac{n}{i}\right)^{2} \\ f(p) & = p^{2} - 1 \\ f(p^{k}) & = p^{2k} - p^{2k - 2} \end{align*} $$

时间复杂度:$\mathcal O(\sqrt{n})$,其中 $n = 10^{14}$。


Code

答案:$94586478$。

#include <bits/stdc++.h>
typedef long long int64;

const int N = 1e7 + 5, MOD = 1e9 + 7;
int n, tot, prime[N], f[N];

inline void add(int &x, const int y) {
    (x += y) >= MOD && (x -= MOD);
}
void sieve(int n) {
    std::bitset<N> flg;
    f[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!flg[i]) {
            prime[++tot] = i;
            f[i] = (int64)i * i % MOD - 1;
        }
        for (int j = 1; j <= tot && i * prime[j] <= n; j++) {
            flg[i * prime[j]] = 1;
            if (i % prime[j] == 0) {
                f[i * prime[j]] = (int64)f[i] * prime[j] % MOD * prime[j] % MOD;
                break;
            }
            f[i * prime[j]] = (int64)f[i] * ((int64)prime[j] * prime[j] % MOD - 1) % MOD;
        }
    }
}
int main() {
    int64 n = 1e14;
    sieve((int)sqrt(n));
    int ans = 0;
    for (int i = 1; (int64)i * i <= n; i++) {
        add(ans, (int64)(n / ((int64)i * i)) % MOD * f[i] % MOD);
    }
    printf("%d\n", ans);
    return 0;
}
最后修改:2021 年 05 月 06 日
如果觉得我的文章对你有用,请随意赞赏