Codeforces 1325E Ehab's REAL Number Theory Problem
Description
给一些数,每个的因数个数不超过 ,求最少选出多少个,使得乘积为完全平方。无解输出 。
Solution
「每个的因数个数不超过 」看上去非常玄学,它的本质是什么?
唯一分解定理:任何一个大于 的自然数 ,可以唯一分解成有限个质数的乘积。即:
这里 ,,且 ,正确性显然。
约数个数定理:任何一个大于 的自然数 ,它的约数个数为:
显然对于每一种质因子,都有选 个,选 个……选 个共 种选法,根据乘法原理,当然是它们的乘积。
好,我们用一下约数个数定理。设想 有 种质因数,那么 最小应当是 ,和 矛盾,所以, 至多有 种质因子。
所以, 要么是 ,要么可以表示为 的形式,要么可以表示为 的形式。不难发现把 对 取模不会对答案造成影响,这是因为一个数本身的平方因子可以直接相消了。
现在, 只会是 ,, 三种可能了。
- 如果一个 ,直接输入 ,结束程序,因为直接选它就好了;
- 如果一个 ,那么,建一条边,把 和 连起来;
- 如果一个 ,那么,建一条边,把 和 连起来。
注意 的值可能很大,需要离散化,可以在线性筛的时候预处理。
现在得到了一个图,答案就是这个图的 最小环 的大小。
为什么?选择一个数,就是选择一条边,如果我们选了一个环,那么环上的每个 都有两条边相连,也就是乘了 次,那么这当然是一个完全平方数了!
以内质数大概是 个,这个数字记作 。
用 Floyd 算法 求最小环是行不通的。
因为边权为 ,可以枚举起点然后 BFS,当然,这样直接做的复杂度是 ,当然也是行不通的。(枚举起点 ,单次 BFS 是 ,因为有 条边)
深入剖析,发现 一个环内必然有一个点 ,这是因为不会有两个大于 的点之间有连边,只要这个较小数作为起点被枚举了,那么这个环就必然会被 BFS 到。所以,起点只要枚举到 即可。
当然,必然点都是质数,所以我们记 以内的质数个数为 ,这个算法的时间复杂度就是 ,可以通过。
当然我的代码偷个懒是直接枚举到 的……
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | #include <bits/stdc++.h> #define REP(i, x, y) for(register int i = x; i <= y; i++) using namespace std; const int N = 1e5 + 5, A = 1e6 + 5, SQRTA = 1000; const int INF = 0x3f3f3f3f; int n, ncnt, hd, tl, que[N][2], ans = INF; int a[N], prm[N], id[A], h[N], dis[N]; bool npr[A]; struct edge { int v, nxt; } e[A << 1]; void EulerSieve() { for ( int i = 2; i < A; i++) { if (!npr[i]) prm[++prm[0]] = i, id[i] = prm[0] + 1; for ( int j = 1; j <= prm[0] && i * prm[j] < A; j++) { npr[i * prm[j]] = true ; if (i % prm[j] == 0) break ; } } } inline void AddEdge( int u, int v) { e[++ncnt] = (edge){v, h[u]}; h[u] = ncnt; e[++ncnt] = (edge){u, h[v]}; h[v] = ncnt; } void Divide( int x) { int p[4] = {0}, k[4] = {0}; for ( int i = 1; i <= prm[0] && prm[i] * prm[i] <= x; i++) { if (x % prm[i] == 0) { p[++p[0]] = prm[i]; while (x % prm[i] == 0) k[p[0]] ^= 1, x /= prm[i]; if (!k[p[0]]) p[0]--; } } if (x > 1) p[++p[0]] = x, k[p[0]] = 1; if (!p[0]) { cout << 1 << endl; exit (0); } else if (p[0] == 1) AddEdge(1, id[p[1]]); else AddEdge(id[p[1]], id[p[2]]); } void Bfs( int s) { memset (dis, 0x3f, sizeof dis); dis[s] = 0; que[1][0] = s; que[1][1] = 0; hd = tl = 1; while (hd <= tl) { int u = que[hd][0], fa = que[hd][1]; hd++; for ( int i = h[u]; i; i = e[i].nxt) { int v = e[i].v; if (v == fa) continue ; if (dis[v] == INF) { tl++; que[tl][0] = v; que[tl][1] = u; dis[v] = dis[u] + 1; } else ans = min(ans, dis[u] + dis[v] + 1); } } } int main() { cin >> n; REP(i, 1, n) cin >> a[i]; EulerSieve(); REP(i, 1, n) Divide(a[i]); REP(i, 1, SQRTA) Bfs(i); if (ans == INF) cout << -1 << endl; else cout << ans << endl; return 0; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探