洛谷P3911 最小公倍数之和 题解 莫比乌斯反演

题目链接:https://www.luogu.com.cn/problem/P3911

题目大意:

给你一个长度为 \(N\) 的数列 \(A_1, A_2, \ldots, A_N\),求

\[\sum_{i=1}^N \sum_{j=1}^N \operatorname{lcm}(A_i, A_j) \]


解题思路:

\(M\) 表示 \(A\) 数组中所有元素的最大值,即

\[M = \max_{1 \le i \le N} a_i \]

\(C_x\) 表示数字 \(x\)\(A\) 数组中的出现次数,则答案为

\[\sum_{i=1}^M \sum_{j=1}^M \operatorname{lcm}(i, j) \cdot C_i \cdot C_j \]

由于 \(\operatorname{lcm}(i, j) = \frac{i \cdot j}{\gcd(i, j)}\)

所以答案可以表示为

\[\sum_{i=1}^M \sum_{j=1}^M \frac{i \cdot j}{ \gcd(i, j) } \cdot C_i \cdot C_j \]

如果我们令 \(d = \gcd(i, j)\),然后枚举 \(d\),可以得到答案为

\[\sum_{d=1}^M \sum_{i=1}^M \sum_{j=1}^M [ \gcd(i, j) = d ] \cdot \frac{i \cdot j}{d} \cdot C_i \cdot C_j \]

这里,中括号是艾弗森运算符,成立为 \(1\),不成立为 \(0\)

上式等价于

\[\sum_{d=1}^{M} d \sum_{i=1}^{M/d} \sum_{j=1}^{M/d} [\gcd(i,j) = 1] \cdot (i \cdot C_{id}) \cdot (j \cdot C_{jd}) \]

接下来引入莫比乌斯反演

莫比乌斯反演最常用的性质是:

\[[\gcd(i,j)=1] = \sum_{k \mid \gcd(i,j)} \mu(k) \]

代入上方刚才推导的式子的答案为

\[\sum_{d=1}^{M} d \sum_{k=1}^{M/d} \mu(k) \sum_{k \mid i, i \le M/d} \sum_{k \mid j, j \le M/d} (i \cdot C_{id}) \cdot (j \cdot C_{jd}) \]

这个时候,最右边的两个 sigma 是可以化简的

\(ik\) 表示 \(i\)\(jk\) 表示 \(j\),即可以将

\[\sum_{k \mid i, i \le M/d} \sum_{k \mid j, j \le M/d} (i \cdot C_{id}) \cdot (j \cdot C_{jd}) \]

化简为

\[\sum_{i=1}^{M/(dk)} \sum_{j=1}^{M/(dk)} (ik \cdot C_{idk}) \cdot (jk \cdot C_{jdk}) \]

\[= k^2 \left( \sum_{i=1}^{M/(dk)} i \cdot C_{idk} \right)^2 \]

代入到答案的公式得,答案为

\[\sum_{d=1}^{M} d \sum_{k=1}^{M/d} \mu(k) \cdot k^2 \left( \sum_{i=1}^{M/(dk)} i \cdot C_{idk} \right)^2 \]

此时,计算上述式子需要三重循环,会超时。

\(T = dk\),然后将原来的 “枚举 \(d\)\(k\)” 转变为 “枚举 \(T\)\(d\)”,则答案的式子转换为

\[\sum_{T=1}^M \sum_{d \mid T} d \cdot \mu(\frac{T}{d}) \cdot (\frac{T}{d})^2 \left( \sum_{i=1}^{M/T} i \cdot C_{iT} \right)^2 \]

再转换一下就是

\[\sum_{T=1}^M \sum_{d \mid T} T \cdot \mu(\frac{T}{d}) \cdot (\frac{T}{d}) \cdot \left( \sum_{i=1}^{M/T} i \cdot C_{iT} \right)^2 \]

\(T\) 提到最前面来,最后那个 sigma 用 \(d\) 替换 \(\frac{T}{d}\),有

\[\sum_{T=1}^M T \left( \sum_{d \mid T} \mu(d) \cdot d \right) \cdot \left( \sum_{i=1}^{M/T} i \cdot C_{iT} \right)^2 \]

第一个括号中的 sigma 可以 \(O(M \log M)\) 预处理得到,然后查询就是 \(O(1)\) 了。

第二个括号中的 sigma 可以直接暴力,暴力时间复杂度 \(O(M/T)\)

\(O(T \cdot (M / T)) = O(M^2)\)

所以总时间复杂度为 \(O(M^2)\)

示例程序:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 5e4, maxn = N + 5;

int n, c[maxn], m, mu[maxn];
long long sum[maxn];

int main() {
    scanf("%d", &n);
    for (int i = 0, a; i < n; i++) {
        scanf("%d", &a);
        c[a]++;
        m = max(m, a);
    }
    mu[1] = 1;
    for (int i = 2; i <= m; i++) {
        mu[i] = -1;
        for (int j = 2; j * j <= i; j++) {
            if (i % j == 0) {
                if (i / j % j)
                    mu[i] = mu[i / j] * (-1);
                else
                    mu[i] = 0;
                break;
            }
        }
    }
    for (int i = 1; i <= m; i++) {
        for (int d = 1; d * d <= i; d++) {
            if (i % d == 0) {
                sum[i] += mu[d] * d;
                if (d * d < i)
                    sum[i] += mu[i/d] * (i/d);
            }
        }
    }
    ll ans = 0;
    for (int t = 1; t <= m; t++) {
        ll tmp = 0;
        for (int i = 1; i <= m/t; i++)
            tmp += i * c[i * t];
        ans += 1ll * t * sum[t] * tmp * tmp;
    }
    printf("%lld\n", ans);
    return 0;
}
posted @ 2026-05-13 09:22  quanjun  阅读(6)  评论(0)    收藏  举报