P2568 GCD
- 题目地址: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\)互质的整数数量。因此所有情况可以分为三类:
- 当 \(a<b\)时,固定 \(b=k\ge2\),有 \(\varphi(k)\)种合法的 \(a\);
- 当 \(a>b\)时,根据对称性,数量相同;
- 当 \(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;
}

P2568 GCD
浙公网安备 33010602011771号