P1390 公约数的和 题解

传送门
题意:求出

\(\sum\limits_{i=1}^{n}\sum\limits_{j=i+1}^{n}\gcd(i,j)\)

原式
\(=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{i - 1}\gcd(i,j)\)

\(=\sum\limits_{d=1}^n\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{i - 1}[gcd(i,j) = d]\)

\(=\sum\limits_{d=1}^n\sum\limits_{i=1}^{\frac{n}{d}}\sum\limits_{j=1}^{i-1}d\times [gcd(i,j) = 1]\)

\(=\sum\limits_{d=1}^nd\times \sum\limits_{i=1}^{\frac{n}{d}}\varphi(i)\)

令:\(phi(x) =\sum\limits_{i=1}^x\varphi(i)\)
原式:
\(=\sum\limits_{d=1}^nd\times phi(\frac{n}{d})\)

注意:这一题中 \(\varphi(1) = 0\),因为求和时是从 1 至 i - 1。
这里可以用整除分块来做,时间复杂度:\(O(n+T\sqrt n)\)

AcCode:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int N = 2e6, inf = 1e9, P = inf + 7;
int v[N + 1], cnt[N + 1];
ll phi[N + 1];
vector<int> ve;

void init() {
	phi[1] = 0;
	for (int i = 2; i <= N; i++) {
		if (!v[i]) {
			v[i] = i;
			phi[i] = i - 1;
			ve.push_back(i);
		}
		for (auto j : ve) {
			if (j > i || j > N / i) break;
			v[i * j] = j;
			phi[i * j] = phi[i] * (i % j ? j - 1 : j);
		}
	}
	for (int i = 1; i <= N; i++)
		phi[i] += phi[i - 1];
}

int main() {
	init();
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		int n;
		scanf("%d", &n);
		if (n == 0)
			break;
		ll ans = 0;
		for (int d = 1; d <= n; d++) {
			int k = n / (n / d);
			ans += phi[n / d] * (d + k) * (k - d + 1) / 2;
			d = k;
		}
		printf("%lld\n", ans);
	}
	return 0;
}
posted @ 2023-01-14 15:31  weirdoX  阅读(36)  评论(0)    收藏  举报