CF870F

CF870F

题意

给定一张 \(n\) 个顶点的图,对于点 \(i,j\),如果 \(\gcd(i,j)\neq 1\),则 \(i\)\(j\) 有一条长度为 \(1\) 的无向边。

\(dis(i,j)\) 表示从 \(i\)\(j\) 的最短路,如果 \(i\) 无法到 \(j\),则 \(dis(i,j)=0\)。求节点两两之间距离之和。

Tips: \(n \leq 10^7\)

题解

一个分类讨论直接秒了。

方便起见,我们记 \(p_i\)\(i\) 的最小质因子, \(num_i\)\(i\) 是最小质因子出现的个数。

Case A

两两不互质

那么可以直接到达,距离为1。

贡献 \(1 \times \sum_{i=1}^{n}\sum_{j=i+1}^{n}[\gcd(i,j) \neq 1]\)

枚举 \(i\), 然后欧拉函数随便做。

答案是 \(\binom{n-1}{2} - \sum_{i=1}^{n}(\varphi_i - 1)\)

Case B

两两互质,且 \(p_ip_j \leq n\)

\(p_ip_j\) 作为中转站,距离为2。

贡献 \(2 \times \sum_{i=1}^{n}\sum_{j=i+1}^{n}[\gcd(i, j)=1][p_ip_j \leq n]\)

统计的话,总方案数减去 Case A、C、D 的就行了。

Case C

两两互质,且 \(p_ip_j > n(p_i \leq \frac{n}{2}\)\(p_j \leq \frac{n}{2})\)

那就先到 \(2p_i\) 再到 \(2p_j\) 最后到 \(j\), 距离为3。

贡献 \(3 \times \sum_{i=1}^{n}\sum_{j=i+1}^{n}[p_i\leq \frac{n}{2}][p_j \leq \frac{n}{2}][p_ip_j > n]\)

化简一下,枚举最小质因子。

\(\sum_{p \in \mathbb{P}}num_p\sum_{q \in \mathbb{P}, p<q, q \leq \frac{n}{2}, pq \leq n} num_q\)

然后我们枚举 \(p\), q可以发现是连续的一段,前缀和即可,区间是 \([\max({p+1,\dfrac{n}{p}+1}),\dfrac{n}{2}]\)

Case D

两两互质,且\(p_ip_j > n(p_i > \dfrac{n}{2}\)\(p_j > \dfrac{n}{2})\)

那就到达不了,但要统计一下方案数。

贡献 \(0 \times \sum_{i=1}^{n}\sum_{j=i+1}^{n}[\gcd(i,j)=1][p_i > \dfrac{n}{2}][p_j > \dfrac{n}{2}][p_ip_j > n]\)

跟 Case C 同理化简,然后前缀和,区间查就行了。

Code

Talk is useless, we see the code.

#include <bits/stdc++.h>
using ll = long long;
static const int N = 1e7 + 5;
int n, cnt; ll ans, ans0, ans1, ans2, ans3;
int a[N], c[N], p[N], prime[N];
ll phi[N]; bool vis[N];
void sieve(int n) {
    phi[1] = 1; vis[1] = 1;
    for (int i = 2; i <= n; ++i) {
        if (!vis[i]) prime[++ cnt] = i, p[i] = i, phi[i] = i - 1;
        for (int j = 1; 1ll * i * prime[j] <= n; ++j) {
            vis[i * prime[j]] = true;
            p[i * prime[j]] = prime[j];
            phi[i * prime[j]] = phi[i] * (i % prime[j] ? prime[j] - 1 : prime[j]);
            if (i % prime[j] == 0) break;
        }
    }
}
ll ask(int l, int r) {return l > r ? 0 : c[r] - c[l - 1];}
signed main() {
    scanf("%d", &n); sieve(n);
    for (int i = 1; i <= n; ++i) phi[i] += phi[i - 1];
    for (int i = 2; i <= n; ++i) ++ a[p[i]];
    for (int i = 1; i <= n; ++i) c[i] += c[i - 1] + a[i];
    ans1 = 1ll * (n - 1) * (n - 2) / 2 + n - phi[n];
    for (int i = 1; i <= cnt; ++i) {
        int x = prime[i];
        int l = std::max(x, n / x) + 1, r = n / 2;
        ans3 += ask(l, r) * a[x];
    }
    for (int i = 1; i <= cnt; ++i) {
        int x = prime[i];
        int l = std::max(x, n / 2) + 1, r = n;
        ans0 += ask(l, r) * a[x];
    }
    ans2 = 1ll * (n - 1) * (n - 2) / 2 - ans0 - ans1 - ans3;
    ans = 0 * ans0 + 1 * ans1 + 2 * ans2 + 3 * ans3;
    return printf("%lld\n", ans), 0; 
}
posted @ 2023-01-10 20:42  xxcxu  阅读(23)  评论(0编辑  收藏  举报