CF1325E - Ehab's REAL Number Theory Problem(最小環)
阿新 • • 發佈:2021-09-28
題目
有\(n\)個數,每個數至多隻有7個因子。問從中最少取多少個數相乘結果為完全平方數。
題解
完全平方數就是質因子數冪次都為偶數。對於每個數\(p_1^{c_1}...p_k^{c_k}\),可以把冪次對2取模,這樣就可以寫成\(p_1...p_k\)。由於至多隻有7個因子,所以每個數至多隻有2個質因數。如果沒有質因數,那麼說明找到一個完全平方數,答案為1。否則設這兩個質因數為\(p,q\)(如果只有1質因子個那麼就令另一個為1)。對於每個數都有一對\((p,q)\),把這個數對看作一個無向邊。這些邊構成的圖中,每個環就對應這完全平方數的取法!所以問題轉換為求無向圖的最小環。
如果有重邊,那麼最小環長度為2;否則對於邊權為1的圖來說,求最小環的複雜度為\(O(n^2)\)
但是對於在這題的限制下,兩個相鄰結點的值不會超過\(\sqrt{\max(a_i)}\),否則邊對應的數就超過\(max(a_i)\)。這說明每個環都至少包含一個結點值小於\(\sqrt{\max(a_i)}\)。所以只需對小於\(\sqrt{\max(a_i)}\)的結點bfs就可以確保每個環都考慮到了。
時間複雜度\(O(n\sqrt{M})\),\(M\)為\(n\)個數的最大值。
#include <bits/stdc++.h> #define endl '\n' #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0) #define mp make_pair #define seteps(N) fixed << setprecision(N) typedef long long ll; using namespace std; /*-----------------------------------------------------------------*/ ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;} #define INF 0x3f3f3f3f const int N = 1e6 + 10; const double eps = 1e-5; typedef pair<int, int> PII; bool isnp[N]; vector<int> d[N]; vector<PII> ed; int vis[N], tag; int len[N],fa[N]; vector<int> np[N]; int bfs(int p) { int res = INF; queue<int> q; q.push(p); fa[p] = 0; vis[p] = tag; len[p] = 0; while(!q.empty()) { int cur = q.front(); q.pop(); for(int nt : np[cur]) { if(nt == fa[cur]) continue; if(vis[nt] == tag) { res = min(res, len[nt] + len[cur] + 1); } else { len[nt] = len[cur] + 1; vis[nt] = tag; fa[nt] = cur; q.push(nt); } } } return res; } int main() { IOS; isnp[1] = 1; for(int i = 2; i < N; i++) { if(!isnp[i]) { d[i].push_back(i); for(int j = 2 * i; j < N; j += i) { d[j].push_back(i); isnp[j] = 1; } } } int ans = INF; int n; int mx = 0; cin >> n; for(int i = 1; i <= n; i++) { int x; cin >> x; mx = max(x, mx); bool flag = 1; vector<int> tmp; for(int di : d[x]) { int tx = x, cnt = 0; while(tx % di == 0) { tx /= di; cnt++; } if(cnt % 2) tmp.push_back(di); } if(tmp.empty()) { ans = 1; } else if(tmp.size() == 1) { ed.push_back({1, tmp[0]}); } else { ed.push_back({tmp[0], tmp[1]}); } } if(ans == INF) { sort(ed.begin(), ed.end()); int m = unique(ed.begin(), ed.end()) - ed.begin(); if(m == ed.size()) { for(int i = 0; i < m; i++) { int u = ed[i].first, v = ed[i].second; np[u].push_back(v); np[v].push_back(u); } for(int i = 1; i * i <= mx; i++) { tag++; ans = min(ans, bfs(i)); } } else { ans = 2; } } if(ans == INF) cout << -1 << endl; else cout << ans << endl; }