P2568 GCD

题目描述


给定正整数 \(n\),求 \(1\le x,y\le n\) 且 \(\gcd(x,y)\) 为素数的数对 \((x,y)\) 有多少对。

分析


由题目给出样例我们知道,这里所求的数对是有序数对。

假设 \(gcd(x,y)=p\), \(p\)为素数,则有 \(gcd({x\over p},{y\over p})=1\),令 \(a={x\over p},b={y\over p}\rightarrow 1\leq a,b\leq \lfloor{n\over p}\rfloor\)。因此,设 \(F(m)\)表示 \(1\leq a,b\leq m\)的互质有序数对个数,就有:

\[\boxed{ans=\sum_{p\leq n\ and\ p是素数}F(\lfloor{n\over p}\rfloor)} \]

欧拉函数 \(\varphi(k)\)表示 \(1\leq t\leq k\)中,与 \(k\)互质的整数数量。因此所有情况可以分为三类:

  1. 当 \(a<b\)时,固定 \(b=k\ge2\),有 \(\varphi(k)\)种合法的 \(a\);
  2. 当 \(a>b\)时,根据对称性,数量相同;
  3. 当 \(a=b\)时,只有 \((1,1)\)互质。
    所以:

\[F(m)=2\sum_{k=2}^m\varphi(k) + 1=2\sum_{k=1}^m\varphi(k) - 1 \]

定义欧拉函数的前缀和:

\[S(m)=\sum_{k=1}^m\varphi(k) \]

最终的答案就是:

\[\boxed{ans=\sum_{p\leq n\ and\ p是素数}(2S(\lfloor{n\over p}\rfloor) - 1)} \]

#include <iostream>
#include <vector>

int main() {
    unsigned n;
    scanf("%u", &n);
    std::vector<unsigned int> primes;
    std::vector<bool> isPrime(n + 1, true);
    std::vector<unsigned long long> phi(n + 1, 0);
    isPrime[0] = isPrime[1] = false;
    phi[1] = 1;
    for (unsigned int i = 2; i <= n; i++) {
        if (isPrime[i]) {
            primes.push_back(i);
            phi[i] = i - 1;
        }
        for (unsigned int pj : primes) {
            if (1LL * i * pj > n) break;
            isPrime[i * pj] = false;
            if (i % pj == 0) {
                phi[i * pj] = phi[i] * pj;
                break;
            } else {
                phi[i * pj] = phi[i] * (pj - 1);
            }
        }
    }
    unsigned long long preSum = 0;
    for (unsigned int i = 1; i <= n; i++) {
        preSum += phi[i];
        phi[i] = preSum;
    }
    // ans
    unsigned long long ans = 0;
    for (unsigned int p : primes) {
        ans += 2 * phi[n / p] - 1;
    }
    printf("%llu", ans);
    return 0;
}
posted @ 2026-09-10 14:49  chen_xing  阅读(10)  评论(0)    收藏  举报