【GESP】C++五级真题(数论, 贪心思想考点) luogu-B4070 [GESP202412 五级] 奇妙数字
GESP C++ 2024年12月五级真题,数论和贪心思想考点,又见质因数分解,5级似乎很喜欢考这个题型,题目难度⭐⭐⭐☆☆,五级正常难度。洛谷难度等级普及/提高−
luogu-B4070 [GESP202412 五级] 奇妙数字
题目要求
题目描述
小杨认为一个数字 $x$ 是奇妙数字当且仅当 $x=p^a$,其中 $p$ 为任意质数且 $a$ 为正整数。例如,$8=2^3$,所以 $8$ 是奇妙的,而 $6$ 不是。
对于一个正整数 $n$,小杨想要构建一个包含 $m$ 个奇妙数字的集合 ${x_1,x_2,\cdots,x_m}$,使其满足以下条件:
- 集合中不包含相同的数字。
- $x_1\times x_2\times \cdots\times x_m$ 是 $n$ 的因子(即 $x_1,x_2,\cdots,x_m$ 这 $m$ 个数字的乘积是 $n$ 的因子)。
小杨希望集合包含的奇妙数字尽可能多,请你帮他计算出满足条件的集合最多包含多少个奇妙数字。
输入格式
第一行包含一个正整数 $n$,含义如题面所示。
输出格式
输出一个正整数,代表满足条件的集合最多包含的奇妙数字个数。
输入输出样例 #1
输入 #1
1
128
输出 #1
1
3
说明/提示
样例解释
关于本样例,符合题意的一个包含 $3$ 个奇妙数字的集合是 ${2,4,8}$。首先,因为 $2=2^1$,$4=2^2$,$8=2^3$,所以 $2,4,8$ 均为奇妙数字。同时,$2\times 4\times 8=64$ 是 $128$ 的的因子。
由于无法找到符合题意且同时包含 $4$ 个奇妙数字的集合,因此本样例的答案为 $3$。
数据范围
对于 $100\%$ 的数据,保证 $2\le n\le 10^{12}$。
| 子任务编号 | 得分占比 | $n$ |
|---|---|---|
| $1$ | $20\%$ | $\le 10$ |
| $2$ | $20\%$ | $\le 1\,000$ |
| $3$ | $60\%$ | $\le 10^{12}$ |
题目分析
解题思路
问题本质
给定正整数 $n\le 10^{12}$,求其质因数分解后,每个质数 $p$ 的指数 $e$ 最多能拆成多少组互不相同的正整数之和(即 $1+2+\cdots+k\le e$ 的最大 $k$)。
最终答案为所有质数对应 $k$ 的总和——这就是能选出的“奇妙数字”的最大个数。- 关键观察
- 奇妙数字只能是 $p^k$($p$ 为质数,$k\ge 1$)。
- 对于同一个质数 $p$,若其总指数为 $e$,则我们最多能选出 $k$ 个互不相同的 $p^1,p^2,\dots,p^k$,满足 $1+2+\cdots+k\le e$。
贪心:从 $k=1$ 开始依次消耗指数,直到剩余指数不足下一个 $k+1$ 为止。 - 不同质数之间互不影响,直接累加各自的 $k$ 即可。
- 算法步骤
- 对
n做质因数分解,得到std::map<long long, int> factor_mp存储的{(p1,e1),…,(pt,et)}。 对每个
(p,e),计算最多能拆出的组数k:1 2 3 4 5
int k = 0; while (e >= k + 1) { ++k; e -= k; }
累加
k到总答案。- 最终输出累加后的总
k即为答案。
- 对
- 复杂度
- 时间:$O(\sqrt{n})$,试除法分解质因数。
- 空间:$O(\log n)$,仅存储质因子及其指数。
示例代码
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
#include <iostream>
#include <map>
int main() {
long long n; // 读入待分解的正整数 n(2 ≤ n ≤ 1e12)
std::cin >> n;
std::map<long long, int> factor_mp; // 用 map 存储质因子及其出现次数(自动按质数升序)
// 试除法:从小到大枚举可能的质因子 i
for (long long i = 2; i * i <= n; i++) {
int times = 0; // 统计当前质数 i 的幂次
while (n % i == 0) { // 能整除就继续除
times++;
n /= i;
}
if (times > 0) { // 若 i 确实是质因子,记录
factor_mp.insert({i, times});
}
}
// 若剩余 n > 1,则它本身是一个大于 sqrt(原 n) 的质因子
if (n > 1) {
factor_mp.insert({n, 1});
}
int count = 0; // 统计最多能选出的“奇妙数字”个数
// 对每个质因子 p^e,我们要把它拆成尽可能多的互不相同的 p^k 形式
// 贪心策略:依次选 p^1, p^2, p^3…,直到把 e 用完
for (auto &f : factor_mp) {
int total_times = f.second; // 该质数的总幂次
for (int i = 1; i <= total_times; i++) {
count++; // 选了一个 p^i
total_times -= i; // 消耗掉 i 次幂
}
}
std::cout << count; // 输出最多能选出的奇妙数字个数
return 0;
}
所有代码已上传至Github:https://github.com/lihongzheshuai/yummy-code
GESP 学习专题站:GESP WIKI
“luogu-”系列题目可在洛谷题库进行在线评测。
“bcqm-”系列题目可在编程启蒙题库进行在线评测。
欢迎加入:Java、C++、Python技术交流QQ群(982860385),大佬免费带队,有问必答
欢迎加入:C++ GESP/CSP认证学习QQ频道,考试资源总结汇总
欢迎加入:C++ GESP/CSP学习交流QQ群(688906745),考试认证学员交流,互帮互助
