AcWing 5416. 因子化简【质因数分解】

原题链接

5416. 因子化简 - AcWing题库

题目描述

质数(又称“素数”)是指在大于 11 的自然数中,除了 11 和它本身以外不再有其他因数的自然数。

小 P 同学在学习了素数的概念后得知,任意的正整数 n都可以唯一地表示为若干素因子相乘的形式。

如果正整数 n有 m个不同的素数因子 p1,p2,…,pm1,2,…,

小 P 认为,每个素因子对应的指数 ti反映了该素因子对于 n的重要程度。

现设定一个阈值 k,如果某个素因子 pi对应的指数 ti 小于 k,则认为该素因子不重要,可以将 ptii 项从 n 中除去;反之则将 ptii 项保留。

最终剩余项的乘积就是 n简化后的值,如果没有剩余项则认为简化后的值等于 11。

试编写程序处理 q个查询:

每个查询包含两个正整数 n 和 k,要求计算按上述方法将 n 简化后的值。

输入格式

输入共 q+1 行。

输入第一行包含一个正整数 q,表示查询的个数。

接下来 q行每行包含两个正整数 n 和 k,表示一个查询。

输出格式

输出共 q行。

每行输出一个正整数,表示对应查询的结果。

数据范围

40%40% 的测试数据满足:n≤1000;
80%80% 的测试数据满足:n≤105≤105;
全部的测试数据满足:1<n≤ 且 1<k,q≤10。

输入样例:
3
2155895064 3
2 2
10000000000 10
输出样例:
2238728
1
10000000000
样例解释

查询一:

  • n=23×32×234×107=23×32×234×107
  • 其中素因子 33 指数为 22,107107 指数为 11。将这两项从 n中除去后,剩余项的乘积为 23×234=223872823×234=2238728。

查询二:

  • 所有项均被除去,输出 11。

查询三:

  • 所有项均保留,将 n 原样输出。

难度:简单
时/空限制:1s / 512MB
总通过数:2948
总尝试数:7488
来源:

第32次CCF-CSP计算机软件能力认证

算法标签
题目大意

解决根据给定阈值简化数字的问题,即保留指数大于等于阈值的素因子并计算它们的乘积。

代码的核心思路是
1.对于每个查询,读取数字 n 和阈值 k
2.对 n 进行质因数分解,得到所有素因子及其指数
3.只保留指数大于等于 k 的素因子,并计算它们的乘积
4.输出结果,如果没有符合条件的素因子则输出 1

整体功能
程序接收多个查询,每个查询包含两个整数n和k。程序需要对n进行质因数分解,只保留指数大于等于k的素因子,最后计算这些保留的素因子乘积作为结果。

大家注意一下这个点

找到素因子:当n % i == 0时,i是n的一个素因子(因为所有小于i的因子已经被处理)

这句话的核心是理解质因数分解的一个重要特性:在从小到大遍历可能的因子时,一旦找到能整除 n 的 i,这个 i 必然是素数。
让我用通俗的方式解释这个逻辑:
假设我们正在用代码中的方法分解 n 的质因数:
我们从 i=2 开始,依次检查 i=2,3,4,5,6,... 是否能整除 n
当我们找到第一个能整除 n 的 i 时(即 n% i == 0),这个 i 一定是素数
为什么呢?
假设 i 不是素数,那么它一定有一个小于 i 的因子 j(j < i)
但按照我们的遍历顺序,j 应该已经在 i 之前被检查过了
如果 j 是 i 的因子,且 j 能整除 i,那么 j 也一定能整除 n(因为 i 能整除 n)
这就意味着在检查 i 之前,我们应该已经找到 j 并将 n 中的所有 j 因子都除去了
所以此时 i 不可能再有小于它的因子,因此 i 必定是素数
举个例子:
当 n=12 时,我们的分解过程是:
i=2:12%2==0,找到因子 2(素数)
除去所有 2 的因子:12→6→3,得到 2²
i=3:3%3==0,找到因子 3(素数)
除去所有 3 的因子:3→1,得到 3¹
循环结束
在这个过程中,我们不会检查到 i=4,因为当 i=4 时 n 已经变成 1 了
即使 n 更大,比如 n=84:
我们会先找到 2,处理后 n 变成 21
然后找到 3,处理后 n 变成 7
然后找到 7,处理后 n 变成 1
我们不会检查到 4、6 这些合数,因为它们的因子已经被提前处理了
这就是为什么当 n% i == 0 时,i 一定是素数的原因 —— 所有可能的复合因子都已经被它的素因子提前处理了。
 

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;  // 使用长整型处理大数字

int main()
{
    int m;
    cin >> m;  // 读取查询数量

    while (m -- )  // 处理每个查询
    {
        LL n, k;
        cin >> n >> k;  // 读取当前查询的n和k

        LL res = 1;  // 结果初始化为1
        // 遍历可能的素因子
        for (int i = 2; i <= n / i; i ++ )
            if (n % i == 0)  // 找到一个素因子i
            {
                LL t = 1, c = 0;  // t存储i^c,c是指数
                // 计算i的指数
                while (n % i == 0)
                {
                    n /= i;  // 除去因子i
                    t *= i;  // 累乘i,得到i^c
                    c ++ ;   // 指数加1
                }
                // 如果指数大于等于k,则保留该因子
                if (c >= k) res *= t;
            }

        cout << res << endl;  // 输出结果
    }

    return 0;
}

代码的时间复杂度主要取决于质因数分解的过程,对于每个数 n,分解的时间复杂度是 O (√n)。由于题目约束中 n 最大为 10^10,√n 约为 10^5,而查询数量 q 不超过 10,所以总运算量在可接受范围内。
代码特点
高效性:使用i <= n / i作为循环条件,减少了循环次数
空间优化:直接在原数n上进行分解(不断除以因子),不需要额外存储空间
正确性:针对题目约束(k>1)做了优化,确保结果正确
该代码完全符合题目的要求,能够高效处理所有给定范围内的测试数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值