1. 程式人生 > 其它 >CF1325E - Ehab's REAL Number Theory Problem(最小環)

CF1325E - Ehab's REAL Number Theory Problem(最小環)

題目

\(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)\)

。因為要對每個點都bfs一次計算環。然而,事實上,對於某個點進行bfs,可以遍歷到所有包含該點的環。之所以要對每個點都bfs,是因為在任意圖中,不能確定所有環都被遍歷到了,所以才要對每個點都bfs。

但是對於在這題的限制下,兩個相鄰結點的值不會超過\(\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;
}