图论 + 数论 ---- CF1325E E. Ehab‘s REAL Number Theory Problem (约数个数 + 枚举 + bfs找最小环)[从图结构优化搜索]

题目链接


题目大意:

给你 n n n个数,每个数保证约数个数不超过 7 7 7个。问你从中选出若
干个数的乘积是完全平方数,最少要选择多少个数?,不存在输出-1.


题目思路:

1.每个数约数不超过7个 → \rightarrow 每个数最多只有两个不同的质因子
n = p 1 a 1 p 2 a 2 . . . p n a n n=p_1^{a1}p_2^{a2}...p_n^{an} n=p1a1p2a2...pnan
Number of divisors = ( a 1 + 1 ) ∗ ( a 2 + 1 ) . . ∗ ( a n + 1 ) ≤ 7 \text{Number of divisors}=(a_1+1)*(a_2+1)..*(an+1)\leq7 Number of divisors=(a1+1)(a2+1)..(an+1)7
那么可以解除 n ≤ 2 n\leq2 n2

  1. 我知道平方数里面的质因子的指数都是偶数,那么我们先把偶数的质因子给去掉那么每个质因子要么没有,要么只剩下一个那么 n n n可以表示为 n = p 1 × p 2 n=p_1\times p_2 n=p1×p2我们对 p 1 和 p 2 p_1和p_2 p1p2直接连接无向边,那么要使得是是完全平方数,就是p1,p2,p3要出现偶数个 → \rightarrow 每个点的度数是偶数
  2. 我们要求最小那么每个点的度数最好为2,那么本质上就是找最小环,每个点的度数都是 2 2 2
  3. 无向图最小环 →    F l o y e d    O ( n 3 ) \rightarrow\;Floyed\;O(n^3) FloyedO(n3)直接T飞了!!
  4. 我们观察一下图结构 p 1 ≤ n , p 2 > n p_1\leq\sqrt n,p_2>\sqrt n p1n ,p2>n 就是小点和大点交错连边
  5. 那么我们可以枚举起点,用 b f s bfs bfs去找最小环 , b f s bfs bfs找最小环是保证起点一定在环上面,但是不能枚举所有的点,我们发现 小 点 连 大 点 , 就 是 一 条 边 的 两 端 肯 定 是 一 个 ≥ n , 一 个 小 于 n 小点连大点,就是一条边的两端肯定是一个\ge\sqrt n,一个小于\sqrt n n ,n
  6. 那么我们只要枚举小于 n \sqrt n n 就可以了 也 就 最 多 也 就 1000 也就最多也就1000 1000
    那么就可以A了

AC code

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = N;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
   x = 0;char ch = getchar();ll f = 1;
   while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
   while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
   read(first);
   read(args...);
}
inline void out(int x) {
    if (x > 9) out(x / 10);
    putchar(x % 10 + '0');
}
vector<int> edge[maxn];
int dist[maxn], fa[maxn];
int ans = INF;
void bfs(int u) {
    memset(dist, INF, sizeof(dist));
    dist[u] = 0;
    queue<int> q;
    q.push(u);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int i = 0; i < edge[u].size(); i++) {
            int v = edge[u][i];
            if (v != fa[u]) {
                if (dist[v] != INF) ans = min(ans, (dist[u] + dist[v] + 1));
                else fa[v] = u, dist[v] = dist[u] + 1, q.push(v);;
            }
        }
    }
}
int main() {
    int n, x;
    read(n);
    for (int i = 0; i < n; i++) {
        read(x);
        for (int i = 2; i <= sqrt(x); i++) {
            while (x % (i * i) == 0) x /= i * i;
        }
        if (x == 1) {
            out(1);
            return 0;
        }
        int u = x, v = 1;
        edge[u].push_back(v);
        edge[v].push_back(u);
        for (int i = 2; i <= sqrt(x); i++) {
            if (x % i == 0) {
                u = x / i, v = i;
                edge[u].push_back(v);
                edge[v].push_back(u);
            }
        }
    }
    for (int i = 1; i <= sqrt(maxn); i++) bfs(i);
    if (ans != INF) out(ans);
    else printf("-1");
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值