P2568 GCD

P2568 GCD

大意

求 \(\gcd(x, y) = p\) 的个数。

思路

\[\text{Ans} = \sum_{p \le n} \sum_{i=1}^{\lfloor n/p \rfloor} \sum_{j=1}^{\lfloor n/p \rfloor} [\gcd(i, j) = 1] \]

\[\text{Ans} = \sum_{p \le n} \sum_{d=1}^{\lfloor n/p \rfloor} \mu(d) \lfloor \frac{n}{pd} \rfloor^2 \]

令 \(T = pd\),通过更换求和次序:

\[\text{Ans} = \sum_{T=1}^n \lfloor \frac{n}{T} \rfloor^2 \left( \sum_{p|T, p \in \text{prime}} \mu(\frac{T}{p}) \right) \]

代码

#include<iostream>
using namespace std;

const int MAXN = 1e7 + 5;
bool vis[MAXN];
int mu[MAXN], f[MAXN];
int pr[MAXN], tot;
long long sum[MAXN];

void init(int n){
	mu[1] = 1;
	for(int i = 2;i <= n;i ++){
		if(!vis[i]){
			pr[++ tot] = i;
			mu[i] = -1;
		}
		for(int j = 1;pr[j] * i <= n && j <= tot;j ++){
			vis[pr[j] * i] = 1;
			if(i % pr[j] == 0){
				mu[pr[j] * i] = 0;
				break;
			}
			mu[pr[j] * i] = -mu[i];
		}
	}
	for(int j = 1;j <= tot;j ++){
		for(int i = 1;i * pr[j] <= n;i ++){
			f[i * pr[j]] += mu[i];
		}
	}
	for(int i = 1;i <= n;i ++){
		sum[i] = sum[i - 1] + f[i];
	}
}

void solve(){
	int n, m; cin >> n; m = n;
	if(n > m) swap(n, m);
	long long ans = 0;
	for(int l = 1, r;l <= n;l = r + 1){
		r = min(n / (n / l), m / (m / l));
		ans += (long long)(n / l) * (m / l) * (sum[r] - sum[l - 1]);
	}
	cout << ans << '\n';
}

int main(){
	init(MAXN - 5);
//	int t; cin >> t;
//	while(t --){
		solve();
//	}
	return 0;
}
posted @ 2026-02-27 13:47  To_Carpe_Diem  阅读(19)  评论(0)    收藏  举报