P9488 ZHY 的生成树

题目描述

ZHY 有一个 nnn 个点的完全图,点 uuu 与点 vvv 的距离为 gcd⁡(u,v)\gcd(u,v)gcd(u,v),求这个完全图的最大生成树的边权之和。

输入格式

一个正整数 nnn

输出格式

一个整数,表示这个最大生成树的边权之和。

输入输出样例 #1

输入 #1

4

输出 #1

4

输入输出样例 #2

输入 #2

30

输出 #2

183

输入输出样例 #3

输入 #3

100

输出 #3

1916

说明/提示

本题采用捆绑测试。

Subtask\text{Subtask}Subtask 00\kern{3pt}0(10pts):n≤5n\le 5n5

Subtask\text{Subtask}Subtask 11\kern{3pt}1(20pts):n≤1000n\le 1000n1000

Subtask\text{Subtask}Subtask 22\kern{3pt}2(30pts):n≤106n\le 10^{6}n106

Subtask\text{Subtask}Subtask 33\kern{3pt}3(40pts):n≤107n\le 10^{7}n107

对于所有测试数据,1≤n≤1071\le n \le 10^{7}1n107

C++实现

#include <bits/stdc++.h>
using namespace std;

const int N = 1e7 + 10;
int n, m, fa[N], tot;
int prime[6000100], q, x, k;
bool isp[N];
void Prime() {
	for (register int i = 2; i <= 10000000; ++i) {
		if (isp[i] == 0) prime[++k] = i;
		for (register int j = 1; j <= k && i * prime[j] <= 10000000; ++j) {
			isp[i * prime[j]] = 1;
			if (!(i % prime[j])) break;
		}
	}
}
int find(int x) {
	if(x == fa[x]) return x;
	else return fa[x] = find(fa[x]);
}
void kruskal() {
	int cnt = 0;
	long long sum = 0;
	for(register int i = n / 2; i >= 1; --i) {
		int len = n / i;
		for (int u = 1; prime[u] * i <= n; ++u) {
			int x = find(i), y = find(prime[u] * i);
			++tot;
			if (x != y) {
				++cnt;
				sum += i;
				fa[y] = x;
				if (cnt == n - 1) {
					cout << sum;
					return;
				}
			}
		}
	}
}
signed main() {
	cin >> n;
	Prime();
	for (int i = 1; i <= n; ++i) fa[i] = i;
	kruskal();
	return 0;
}

在这里插入图片描述

后续

接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容

更多推荐