202309-因数分解(luogu-B3871)

202309-因数分解(luogu-B3871)

GESP C++ 2023年9月五级真题,数论考点,难度⭐⭐★☆☆。洛谷难度等级普及−

luogu-B3871 [GESP202309 五级] 因数分解

题目要求

题目描述

每个正整数都可以分解成素数的乘积,例如: 6=2×36=2\times 320=22×520=2^2\times5

现在,给定一个正整数,请按要求输出它的因数分解式。

输入格式

输入第一行,包含一个正整数 NN。约定 2N10122 \le N \le 10^{12}

输出格式

输出一行,为的因数分解式。要求按质因数由小到大排列,乘号用星号 * 表示,且左右各空一格。当且仅当一个素数出现多次时,将它们合并为指数形式,用上箭头 ^ 表示,且左右不空格。

输入输出样例 #1

输入 #1
6
输出 #1
2 * 3

输入输出样例 #2

输入 #2
20
输出 #2
2^2 * 5

输入输出样例 #3

输入 #3
23
输出 #3
23

题目分析

解题思路

NN 做质因数分解,从小到大依次试除 2N2 \rightarrow \sqrt{N}

  1. ii 能整除 NN,则 ii 为质因子,统计其指数;
  2. 每除尽一个因子就把 NN 更新为商,继续试除同一因子直至除不尽;
  3. 若最终剩余 N>1N>1,则该剩余值本身为质数,单独记录;
  4. 按“质因子 * 质因子”格式输出,指数大于 11 时用 ^ 合并,乘号左右各空一格。

在主思路一致的基础上,下面给出了两种不同的实现思路,对比它们的核心区别。

维度方法一(边算边输出)方法二(先存后输出)
输出时机发现因子立即打印全部因子收集完再统一打印
额外空间几乎零额外空间使用 vector 存储所有因子
代码复杂度需维护 flag 控制首尾乘号用下标天然控制分隔符
可扩展性难以二次处理(如排序、格式化)可任意后续处理(如逆序、去重、格式化)
可读性输出与算法耦合,逻辑稍乱算法与输出解耦,结构清晰

建议掌握:方法二

  1. 思路清晰:先完整拿到数据,再决定如何展示,符合“计算-存储-展示”的分层思想。
  2. 便于调试:可随时打印 factors 内容,快速定位因子分解是否正确。
  3. 易扩展:若题目改为“从大到小输出”或“只输出指数大于 1 的因子”,只需改动最后遍历即可。
  4. 竞赛习惯:在算法竞赛中,先收集再统一输出是通用模板,减少因格式错误丢分。

复杂度

试除范围 2N2 \rightarrow \sqrt{N},单次试除 O(N)O(\sqrt{N}),总体 O(N)O(\sqrt{N})

本题NN的数据规模很大,若是O(N)O(N)的算法,会超时。

边界注意

  • NN 本身就是质数时直接输出 NN
  • 指数等于 11 时不输出 ^1
  • 乘号前后必须各有一个空格,行首行尾无多余空格。

示例代码

方法一 直接输出

#include <cmath>
#include <iostream>

int main() {
    long long N;                // 读入待分解的正整数
    std::cin >> N;
    bool flag = false;          // 标记是否已输出过因子,用于控制乘号

    // 试除法枚举 2~√N 的所有可能因子
    for (long long i = 2; i <= std::sqrt(N); i++) {
        if (N % i == 0) {       // i 是 N 的一个质因子
            int count = 0;      // 统计该质因子出现的次数
            while (N % i == 0) {
                count++;
                N /= i;         // 将 i 完全除掉
            }
            if (flag) {
                std::cout << " * "; // 输出乘号,左右各空一格
            }
            flag = true;
            std::cout << i;     // 输出质因子
            if (count > 1) {
                std::cout << "^" << count; // 指数形式
            }
        }
    }
    // 若剩余 N>1,则它本身为质数,直接输出
    if (N > 1) {
        if (flag) {
            std::cout << " * ";
        }
        std::cout << N;
    }
    return 0;
}

方法二 保存因子,再输出

#include <vector>
#include <iostream>
#include <cmath>

int main() {
    long long N;
    std::cin >> N;                          // 读入待分解的正整数
    std::vector<std::pair<long long, int>> factors; // 存储质因子及其指数

    // 试除法枚举 2~√N 的所有可能因子
    for (long long i = 2; i <= std::sqrt(N); i++) {
        if (N % i == 0) {                   // i 是 N 的一个质因子
            int count = 0;                  // 统计该质因子出现的次数
            while (N % i == 0) {            // 将 i 完全除掉
                count++;
                N /= i;
            }
            factors.push_back({i, count});  // 记录质因子及其指数
        }
    }
    // 若剩余 N>1,则它本身为质数,单独记录
    if (N > 1) {
        factors.push_back({N, 1});
    }

    // 按格式输出质因数分解式
    for (size_t i = 0; i < factors.size(); i++) {
        if (i > 0) {
            std::cout << " * ";             // 输出乘号,左右各空一格
        }
        std::cout << factors[i].first;      // 输出质因子
        if (factors[i].second > 1) {
            std::cout << "^" << factors[i].second; // 指数形式
        }
    }
    return 0;
}

本文由coderli.com原创,按照CC BY-NC-SA 4.0 进行授权

所有代码已上传至Github:https://github.com/lihongzheshuai/yummy-code

luogu-”系列题目可在 洛谷题库 在线评测。

bcqm-”系列题目可在 编程启蒙题库 在线评测。

GESP/CSP认证交流QQ群: 688906745

GESP/CSP 认证学习微信公众号
GESP/CSP 认证学习微信公众号
最后更新于