[国家集训队]Crash的数字表格 / JZPTAB 题解

知识点:

Dirichlet 前缀和 + 线性筛。

推导:

默认 \(n \leq m\)

\(ans = \displaystyle \sum_{i = 1}^n \sum_{j = 1}^{m} lcm(i,j) \\ = \displaystyle \sum_{d = 1}^{n} d \sum_{i = 1}^{\lfloor \frac{n}{d} \rfloor} \sum_{j = 1}^{\lfloor \frac{m}{d} \rfloor} ij \\ = \displaystyle \sum_{d = 1}^{n} d \sum_{i = 1}^{\lfloor \frac{n}{d} \rfloor} \sum_{j = 1}^{\lfloor \frac{m}{d} \rfloor} ij \\ = \displaystyle \sum_{d = 1}^{n} d \sum_{k = 1}^{\lfloor \frac{n}{d} \rfloor} \mu(k)k^2 \sum_{i = 1}^{\lfloor \frac{n}{kd} \rfloor} \sum_{j = 1}^{\lfloor \frac{m}{kd} \rfloor} ij\)

下面不妨令 \(T = kd\)。可以得到:

\(ans = \displaystyle \sum_{T = 1}^n T \sum_{d|T} \mu(d)d \sum_{i = 1}^{\lfloor \frac{n}{T} \rfloor} \sum_{j = 1}^{\lfloor \frac{m}{T} \rfloor} ij\)

不妨令 \(g(n, T)\) = \(\displaystyle \sum_{i = 1}^{\lfloor \frac{n}{T} \rfloor}\),可以很容易得到 \(g(T) = (\frac{n}{T} + 1) * \frac{n}{T} / 2\)

那么

\(ans = \displaystyle \sum_{T = 1}^n (T \sum_{d|T} \mu(d)d) \times g(n, T) \times g(m, T)\)

前面的 \(\displaystyle \sum_{d|T} \mu(d)d\) 用 Dirichlet 前缀和预处理即可在 \(O(n \log \log n)\) 的复杂度内完成问题的预处理。

对于询问用整除分块优化即可做到 \(\sqrt{n}\) 处理。

Code

#include <bits/stdc++.h>
using namespace std;
const int Mod = 20101009, MAXN = 1e7 + 5, inv = (Mod + 1) >> 1;
int n, m;
int Prime[MAXN / 11], Mu[MAXN], tot = 0, S[MAXN];
bool bk[MAXN];
void GetPrime(int N) {
    Mu[1] = 1;
    for(int i = 2 ; i <= N ; i ++) {
        if(!bk[i]) Prime[++ tot] = i, Mu[i] = -1; 
        for(int j = 1 ; j <= tot && Prime[j] * i <= N; j ++) {
            bk[Prime[j] * i] = 1;
            if(i % Prime[j] == 0) break;
            Mu[Prime[j] * i] = - Mu[i];
        }
    }
    for(int i = 1 ; i <= N ; i ++) S[i] = 1ll * ((Mu[i] + Mod) % Mod) * i % Mod;
    return ;
}
int Sum(int x) { return 1ll * x * (x + 1) % Mod * inv % Mod; }

int main() {
    cin >> n >> m;
    if(n > m) swap(n, m);
    GetPrime(n);
    for(int i = 1 ; i <= tot ; i ++) 
        for(int j = 1 ; j * Prime[i] <= n ; j ++)
        S[Prime[i] * j] += S[j], S[Prime[i] * j] %= Mod;
    int Ans = 0;
    for(int i = 1 ; i <= n ; i ++) {
        Ans += 1ll * i * S[i] % Mod * Sum(n / i) % Mod * Sum(m / i) % Mod;
        Ans %= Mod;
    }
    cout << Ans;
    return 0;
}
posted @ 2021-07-19 09:31  MYCui  阅读(53)  评论(0编辑  收藏  举报