CF1575G GCD Festival 题解

考虑欧拉反演

\[\sum\limits_{d \mid n} \varphi(d) = n \]

则原式可以化为

\[\begin{align*} &\sum\limits_{i = 1}^n \sum\limits_{j = 1}^n \gcd(a_i, a_j) \cdot \gcd(i, j) \\ = &\sum\limits_{i = 1}^n \sum\limits_{j = 1}^n \gcd(a_i, a_j) \sum\limits_{d \mid \gcd(i, j)} \varphi(d) \\ = &\sum\limits_{d = 1}^n \varphi(d) \sum\limits_{i = 1}^{\lfloor \frac n d \rfloor} \sum\limits_{j = 1}^{\lfloor \frac n d \rfloor} \gcd(a_{id}, a_{jd}) \\ = &\sum\limits_{d = 1}^n \varphi(d) \sum\limits_{i = 1}^{\lfloor \frac n d \rfloor} \sum\limits_{j = 1}^{\lfloor \frac n d \rfloor} \sum\limits_{k \mid \gcd(a_{id}, a_{jd})} \varphi(k) \\ = &\sum\limits_{d = 1}^n \varphi(d) \sum\limits_{k = 1}^{\max\{ a \}} \varphi(k) \left( \sum\limits_{i = 1}^{\lfloor \frac n d \rfloor} [k \mid a_{id}] \right)^2 \\ \end{align*} \]

线性筛 \(\varphi\),预处理 \(a_{id}\) 的所有因数 \(k\)。枚举 \(d\)\(i\),再枚举 \(id\) 的所有因数 \(k\) 计算答案。

时间复杂度 \(O(w + w \sqrt w + n \ln n \sqrt w)\),其中 \(w\) 是值域大小。可以通过。

#pragma GCC optimize("Ofast")

#include <iostream>
#include <map>
#include <vector>

#define int long long

using namespace std;

const int lim = 1e5;
const int mod = 1e9 + 7;

bool vis[lim + 5];
int pr[lim + 5], tail;
int phi[lim + 5];

int n;
int a[100005];
int cnt[100005];
vector<int> factor[100005];

signed main() {
#ifndef ONLINE_JUDGE
    freopen("CF1575G.in", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    phi[1] = 1;
    for (int i = 2; i <= lim; ++i) {
        if (!vis[i]) {
            pr[++tail] = i;
            phi[i] = i - 1;
        }
        for (int j = 1; j <= tail && i * pr[j] <= lim; ++j) {
            vis[i * pr[j]] = 1;
            if (i % pr[j] == 0) {
                phi[i * pr[j]] = phi[i] * pr[j];
                break;
            }
            phi[i * pr[j]] = phi[i] * phi[pr[j]];
        }
    }
    cin >> n;
    int mx = 0;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        mx = max(mx, a[i]);
    }
    for (int i = 1; i <= mx; ++i)
        for (int j = 1; j * j <= i; ++j)
            if (i % j == 0) {
                factor[i].push_back(j);
                if (j * j != i)
                    factor[i].push_back(i / j);
            }
    int ans = 0;
    for (int d = 1; d <= n; ++d) {
        for (int i = d; i <= n; i += d)
            for (auto fac : factor[a[i]])
                ++cnt[fac];
        for (int i = d; i <= n; i += d)
            for (auto fac : factor[a[i]])
                if (cnt[fac]) {
                    ans = (ans + phi[d] * phi[fac] % mod * cnt[fac] % mod * cnt[fac] % mod) % mod;
                    cnt[fac] = 0;
                }
    }
    cout << ans << endl;
    return 0;
}
posted @ 2024-08-22 21:22  bluewindde  阅读(4)  评论(0编辑  收藏  举报