GESP C++五级真题 | 202309 因数分解

四季读书网 3 0
GESP C++五级真题 | 202309 因数分解

点击知行合一Gesp>点击右上角“···”>设为星标🌟

大家好,我是黄老师。 曾任职多家国有大型科技公司,具有多年C/C++实战经验,打造过数百万用户规模的电子终端产品。目前是一名少儿C++编业余讲师,毕竟CSP也自非专😁

已经完成GESP一级保命系列》专栏,GESP二级编程保命-字符图形专栏以及GESP二级编程保命-暴力枚举专栏、GESP三级编程-一维数组GESP三级编程-字符串GESP三级编程-进制转换GESP三级编程-位运算GESP三级编程-排序等等三级专题,供大家参考。

现在推出GESP五级数论系列专栏,并会分享相关实践经验与同学们一起学习、进步🚀

GESP C++五级真题 | 202309 因数分解-第1张图片-四季读书网
GESP C++五级真题 | 202309 因数分解-第2张图片-四季读书网

 往期精选 

GESP C++五级样题 | 小杨的锻炼

GESP C++五级真题 | 202603 有限不循环小数

GESP C++五级真题 | 202406 小杨的幸运数字-质因数分解


GESP四级-二维数组

GESP四级-排序

GESP四级-二维数组

GESP四级-函数

GESP四级-递推递归


GESP认证考级 | 编程题目提交状态AC、WA、TLE……全黑话漂白!

GESP三级C++编程题目汇总贴:2025.11.07

GESP认证考级C++二级保命笔记-嵌套枚举

GESP认证考级C++二级保命笔记-字符图形

GESP认证考级C++一级保命题系列笔记

欢迎关号,共同学习与进步
👍 🌏 ♥️ 🔥 🐳

GESP五级的核心就是“数据结构(链表)+ 基础算法(二分、贪心、分治、递归)+ 数论应用”。备考时,精力可以按 7:3 分配在“算法与数论”和“链表”上。考纲只要求链表,熟练掌握链表的选择、判断题目,满分是首要目标;初等数论与筛法:欧几里得算法、素数筛法、唯一分解定理等,务必掌握代码模版,灵活运用;四大核心算法包括贪心算法、二分算法、分治算法、递归算法

GESP C++五级真题 | 202309 因数分解-第3张图片-四季读书网

质因数分解

GESP C++五级真题 | 202309 因数分解-第4张图片-四季读书网
GESP C++五级真题 | 202309 因数分解-第5张图片-四季读书网

五级

1

GESP 202309 因数分解

GESP C++五级真题 | 202309 因数分解-第6张图片-四季读书网
题目来源

洛谷网B3871

GESP C++五级真题 | 202309 因数分解-第7张图片-四季读书网

↑微信扫码注册信奥公开课小程序↑

五级

2

题解思路

1. 题目分析

核心任务

  • 给定正整数 N(2 ≤ N ≤ 10¹²)

  • 将 N 分解为质因数的乘积,按质因数从小到大输出

  • 输出格式特殊要求:

    • 质因数之间用 * 分隔(星号左右各一个空格)

    • 若某个质因数出现多次(指数 > 1),用 ^ 连接底数和指数(左右不空格)

    • 若指数为 1,不输出指数

样例验证

  • N=6 → 2¹ × 3¹ → 输出 2 * 3 ✓

  • N=20 → 2² × 5¹ → 输出 2^2 * 5 ✓

  • N=23 → 23¹ → 输出 23 ✓

2. 建模思路

直接思路:模拟标准的质因数分解(唯一分解定理)

  • 算法:试除法,从最小的质数 2 开始,不断除以当前质数,直到不能整除为止,记录每个质数的指数

  • 当试除到 p 使得 p×p > N 时停止,若剩余 N > 1,则剩余部分是一个质数

数据范围分析

  • N ≤ 10¹²,因此最多只需要试除到 √N ≤ 10⁶

  • 循环次数最多 10⁶,完全可行(时间复杂度 O(√N))

  • 中间结果使用 long long 类型(最大 10¹²,远小于 9.22×10¹⁸)

3. 算法选择

基础算法:试除法分解质因数

时间复杂度:O(√N) ≈ 10⁶ 次操作,可轻松通过

空间复杂度:O(1)(仅存储因子的临时变量)

优化

  • 单独处理因子 2 后,只试除奇数(减少一半循环)

  • 但本题 N ≤ 10¹²,√N = 10⁶,即使不优化也很轻松

五级

3

试除枚举题解代码

试除枚举解法:

#include<bits/stdc++.h>using namespace std;intmain(){    long long N;    cin >> N;    bool first = true;   // 控制是否输出 "* "    for (long long p = 2; p * p <= N; ++p) {        if (N % p == 0) {            int cnt = 0;            while (N % p == 0) {                N /= p;                cnt++;            }            // 输出因子            if (!first) cout << " * ";            first = false;            cout << p;            if (cnt > 1) cout << "^" << cnt;        }    }    // 如果剩余 N > 1,说明它是一个质因子(指数为1)    if (N > 1) {        if (!first) cout << " * ";        cout << N;    } cout << endl;    return 0;}
GESP C++五级真题 | 202309 因数分解-第8张图片-四季读书网

↑微信扫码注册信奥公开课小程序↑

GESP C++五级真题 | 202309 因数分解-第9张图片-四季读书网

加 VX 联系年卡办理与备考资料领取

五级

4

STL题解参考

1、使用 std::map 存储因子和指数,自动排序
#include<bits/stdc++.h>using namespace std;intmain(){    ios::sync_with_stdio(0);    cin.tie(0); cout.tie(0);    long long N;    cin >> N;    map<long longint> factors;  // 自动按键(质因子)升序排列    for (long long p = 2; p * p <= N; ++p) {        while (N % p == 0) {            factors[p]++;            N /= p;        }    }    if (N > 1) factors[N]++;    // 遍历 map 输出    bool first = true;    for (auto &kv : factors) {        if (!first) cout << " * ";        first = false;        cout << kv.first;        if (kv.second > 1) cout << "^" << kv.second;    }    cout << endl;    return 0;}

特点

  • map 自动按质因子从小到大排序,省去手动维护顺序

  • 代码更清晰,但多了对数级的插入开销(本题可忽略)

2、使用 vector<pair<long long, int>> 存储,手动排序

#include<bits/stdc++.h>using namespace std;intmain(){    ios::sync_with_stdio(false);    cin.tie(0);    long long N;    cin >> N;    vector<pair<long longint>> factors;    for (long long p = 2; p * p <= N; ++p) {        if (N % p == 0) {            int cnt = 0;            while (N % p == 0) {                N /= p;                cnt++;            }            factors.emplace_back(p, cnt);        }    }    if (N > 1) factors.emplace_back(N, 1);    // factors 已经按 p 从小到大插入(循环递增),无需再排序    bool first = true;    for (auto &pr : factors) {        if (!first) cout << " * ";        first = false;        cout << pr.first;        if (pr.second > 1) cout << "^" << pr.second;    }    cout << endl;    return 0;}

特点

  • 使用 vector 更轻量,适合已知顺序的情况

  • 适合需要后续随机访问的场景

3、使用 std::unordered_map 存储因子,再提取排序

#include<bits/stdc++.h>using namespace std;intmain(){    ios::sync_with_stdio(0);    cin.tie(0); cout.tie(0);    long long N;    cin >> N;    unordered_map<long longint> factors;    for (long long p = 2; p * p <= N; ++p) {        while (N % p == 0) {            factors[p]++;            N /= p;        }    }    if (N > 1) factors[N]++;    // unordered_map 无序,需要提取 key 排序    vector<long long> primes;    for (auto &kv : factors) primes.push_back(kv.first);    sort(primes.begin(), primes.end());    bool first = true;    for (long long p : primes) {        if (!first) cout << " * ";        first = false;        cout << p;        if (factors[p] > 1) cout << "^" << factors[p];    }    cout << endl;    return 0;}

特点

  • 哈希表查找 O(1),适合因子数很多的情况(但本题因子数极少)

  • 最后需要排序 keys,额外开销

4、使用 std::multiset 存储所有因子(包括重复),再统计

#include<bits/stdc++.h>using namespace std;intmain(){    ios::sync_with_stdio(0);    cin.tie(0); cout.tie(0);    long long N;    cin >> N;    multiset<long long> ms;  // 存储所有质因子(可重复)    for (long long p = 2; p * p <= N; ++p) {        while (N % p == 0) {            ms.insert(p);            N /= p;        }    }    if (N > 1) ms.insert(N);    // 遍历 multiset 统计每个质因子出现次数    bool first = true;    for (auto it = ms.begin(); it != ms.end(); ) {        long long p = *it;        int cnt = ms.count(p);   // O(log n + cnt)        if (!first) cout << " * ";        first = false;        cout << p;        if (cnt > 1) cout << "^" << cnt;        it = ms.upper_bound(p);  // 跳到下一个不同元素    }    cout << endl;    return 0;}

特点

  • multiset 自动排序,且允许重复

  • 用 count 和 upper_bound 统计频次

  • 代码有趣但效率略低(因为有多次查找)

5、使用 std::stack 存储因子,反向输出(展示栈用法)

#include<bits/stdc++.h>using namespace std;intmain(){    ios::sync_with_stdio(0);    cin.tie(0); cout.tie(0);    long long N;    cin >> N;    stack<pair<long longint>> st;  // 先存后出,可用来反转顺序    for (long long p = 2; p * p <= N; ++p) {        if (N % p == 0) {            int cnt = 0;            while (N % p == 0) {                N /= p;                cnt++;            }            st.push({p, cnt});        }    }    if (N > 1) st.push({N, 1});    // 由于我们是递增试除,但栈是后进先出,所以输出会从大到小    // 但题目要求从小到大,所以这里先把栈元素倒入 vector 再反转输出    vector<pair<long longint>> vec;    while (!st.empty()) {        vec.push_back(st.top());        st.pop();    }    reverse(vec.begin(), vec.end());  // 恢复从小到大    bool first = true;    for (auto &pr : vec) {        if (!first) cout << " * ";        first = false;        cout << pr.first;        if (pr.second > 1) cout << "^" << pr.second;    }    cout << endl;    return 0;}

特点

  • 展示栈的 LIFO 特性,配合反转实现顺序输出

  • 实际不推荐,但体现STL多样性

    GESP C++五级真题 | 202309 因数分解-第10张图片-四季读书网

    加 VX 联系年卡办理与备考资料领取

    -= 扩展思考 =-

    如果 N 扩大到 10¹⁸,√N = 10⁹,试除会超时。此时需要 Miller-Rabin 素性测试 + Pollard Rho 大数分解 算法,这属于高级数论内容。但本题 N ≤ 10¹²,试除法完全足够,体现了根据数据范围选择合适算法的能力。

抱歉,评论功能暂时关闭!