原题链接
题目描述
质数(又称“素数”)是指在大于 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 |
来源: |
算法标签 |
题目大意
解决根据给定阈值简化数字的问题,即保留指数大于等于阈值的素因子并计算它们的乘积。
代码的核心思路是:
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)做了优化,确保结果正确
该代码完全符合题目的要求,能够高效处理所有给定范围内的测试数据。