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;
}
posted @ 2021-09-27 20:33  limil  阅读(23)  评论(0编辑  收藏  举报