题解:洛谷 P10720 小杨的幸运数字
【题目来源】
洛谷:P10720 [GESP202406 五级] 小杨的幸运数字 - 洛谷
【题目描述】
小杨认为他的幸运数字应该恰好有两种不同的质因子,例如,\(12=2×2×3\) 的质因子有 \(2,3\),恰好为两种不同的质因子,因此 \(12\) 是幸运数字,而 \(30\) 的质因子有 \(2,3,5\),不符合要求,不为幸运数字。
小杨现在有 \(n\) 个正整数,他想知道每个正整数是否是他的幸运数字。
【输入】
第一行包含一个正整数\(n\) ,代表正整数个数。
之后 \(n\) 行,每行一个正整数。
【输出】
输出 \(n\) 行,对于每个正整数,如果是幸运数字,输出 \(1\) ,否则输出 \(0\)。
【输入样例】
3
7
12
30
【输出样例】
0
1
0
【核心思想】
-
问题分析:给定 \(n\) 个正整数,判断每个数是否恰好有两个不同的质因子。这是一个质因数分解 + 集合去重问题,核心在于对每个数进行质因数分解并统计不同质因子的个数。
-
算法选择:
- 试除法分解质因数:从 \(2\) 到 \(\sqrt{x}\) 枚举因子,分解并记录不同质因子
- 集合去重:使用
set自动去重,统计不同质因子的数量
-
关键步骤:
- 读入数据:读取 \(n\)
- 逐数判定(对每个数 \(num\)):
- \(calc(num)\):分解质因数
- 枚举 \(i\) 从 \(2\) 到 \(\sqrt{x}\):
- 若 \(x \bmod i = 0\):将 \(i\) 插入集合,然后不断除以 \(i\) 直到不能整除
- 若 \(x > 1\):将剩余的 \(x\) 插入集合(大质因子)
- 返回集合大小
- 枚举 \(i\) 从 \(2\) 到 \(\sqrt{x}\):
- 若 \(calc(num) = 2\):输出
1 - 否则:输出
0
- \(calc(num)\):分解质因数
-
时间/空间复杂度:
- 时间复杂度:\(O(n \cdot \sqrt{V})\),其中 \(V\) 为输入数的最大值
- 空间复杂度:\(O(\log V)\),存储质因子的集合
-
质因数分解与集合去重的核心思想:
- 试除法的效率:只需枚举到 \(\sqrt{x}\),若 \(x\) 有大于 \(\sqrt{x}\) 的质因子,则最多只有一个,最后单独判断
- 集合自动去重:
set容器自动处理重复质因子(如 \(12 = 2^2 \times 3\) 中 \(2\) 只计一次),无需手动判断 - 完全分解的必要性:遇到因子 \(i\) 时必须将所有 \(i\) 的幂次除尽,避免将同一质因子重复计入
- 边界情况:质数(如 \(7\))只有一个质因子,输出 \(0\);\(1\) 没有质因子,输出 \(0\);恰好两个不同质因子的数(如 \(12 = 2^2 \times 3\))输出 \(1\)
- 适用于基础数论分解、质因子统计类入门问题
【算法标签】
普及- #约数
【代码详解】
#include <bits/stdc++.h>
using namespace std;
// 计算一个数的不同质因数个数
int calc(int x) {
set<int> prime_factors; // 使用集合存储不同的质因数
// 分解质因数
for (int i = 2; i * i <= x; i++) {
if (x % i == 0) {
prime_factors.insert(i); // 插入质因数
while (x % i == 0) {
x /= i; // 除去所有该因数
}
}
}
// 处理剩余的大于1的质因数
if (x > 1) {
prime_factors.insert(x);
}
return prime_factors.size(); // 返回不同质因数的个数
}
int main() {
int n;
cin >> n; // 输入数字个数
for (int i = 1; i <= n; i++) {
int num;
cin >> num; // 输入每个数字
// 计算并判断质因数个数是否为2
if (calc(num) == 2) {
cout << "1\n"; // 恰好两个不同质因数
} else {
cout << "0\n"; // 其他情况
}
}
return 0;
}
【运行结果】
3
7
0
12
1
30
0
浙公网安备 33010602011771号