gcd最大生成树模板
Posted suut
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了gcd最大生成树模板相关的知识,希望对你有一定的参考价值。
出处:
ACM International Collegiate Programming Contest, Egyptian Collegiate Programming Contest
Arab Academy for Science, Technology and Maritime Transport, 2017
想法题:n=1e5. 有n*n/2条边,不能kruskal。
但是考虑一下,边权都是gcd,而gcd(x,y)<min(x,y),所以权值不同的数只有1e5个。所以依然用kruskal的想法,枚举所有不同权值的边,然后暴力枚举gcd为该边的两个数,将他们连起来。具体做法就是枚举该边的所有倍数
#include <iostream> #include <vector> #include <cstdlib> #include <algorithm> #include <cstring> #include <cmath> #include<cstdio> #include<vector> #include<ctime> #define rep(i,t,n) for(int i =(t);i<=(n);++i) #define per(i,n,t) for(int i =(n);i>=(t);--i) #define mmm(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int maxn = 1e6+5; const double PI = acos(-1.0); int a[maxn], vis[maxn], f[maxn]; int find(int x) { if (f[x] == x) { return x; }return f[x] = find(f[x]); } int main() { freopen("dream.in", "r", stdin); int t; cin >> t; int n; int x; rep(k, 1, t) { mmm(vis, 0); cin >> n; ll ans = 0; int tot = 0; int mx = 0; rep(i, 1, n) { scanf("%d", &x); if (vis[x]) { ans += x; continue; } vis[x] = 1; f[x] = x; a[++tot] = x; mx = max(mx, x); } int p = 0; for (int i = mx; i&&p < tot - 1; i--) { int x = 0, y; for (int k = 1, tmp; k*i <= mx && p < tot - 1; k++) { if (!vis[tmp = k * i])continue; y = find(tmp); if (!x)x = y; else if (y != x)f[y] = x, ans += i, ++p; } } printf("Case %d: ", k); cout << ans << endl; } //cin >> t; } /* 1 3 4 2 1 2 3 1 2 1 1 4 7 8 9 3 1 1 1 1 1 2 3 4 */ /* 0*/
以上是关于gcd最大生成树模板的主要内容,如果未能解决你的问题,请参考以下文章