用埃氏筛O(nlog(logn))求得1~5e6每个数的质因数个数,用并查集来维护连通块的大小,合并时判断两个数的最大公约数是否含有两个以上的质因数,如果是则合并,最后遍历所有位置,输出最大连通块大小即可。维护连通块不难,建图用dfs搜索也可以实现。困难的是想到可以用gcd的约数个数判断是否优雅,和在nlogn时间内处理出每个数的质因数个数。(我最开始是对每个数分解质因数,结果是超时了),考验的是对gcd和素数筛的理解。
#include <iostream> #include<cstring> #include<algorithm> #include<unordered_set> #define int long long #define endl '\n' using namespace std; typedef pair<int, int> PII; const int N = 1e6 + 10; int cnt[5000010]; bool st[5000010]; int a[N], p[N], sz[N]; int find(int x) { if (x != p[x])p[x] = find(p[x]); return p[x]; } void merge(int x, int y) { x = find(x);y = find(y); if (x != y) { p[y] = p[x]; sz[x] += sz[y]; } } void init() { int N = 5e6; for (int i = 2;i <= N;i++) { if (st[i])continue; for (int j = i+i;j <= N;j += i) { cnt[j]++; st[j] = true; } } } signed main() { cin.tie(0)->sync_with_stdio(0); cout.tie(0); init(); int n;cin >> n; for (int i = 1;i <= n;i++) { p[i] = i, sz[i] = 1; } for (int i = 1;i <= n;i++) cin >> a[i]; for (int i = 1;i < n;i++) { int l, r; cin >> l >> r; int gd = __gcd(a[l], a[r]); if (cnt[gd] >= 2)merge(l, r); } int res = 0; for (int i = 1;i <= n;i++) { if (p[i] == i)res = max(res, sz[i]); } cout << res << endl; return 0; }