质数(又称“素数”)是指在大于 1 1 1 的自然数中,除了 1 1 1 和它本身以外不再有其他因数的自然数。
小 P 同学在学习了素数的概念后得知,任意的正整数 n n n 都可以唯一地表示为若干素因子相乘的形式。如果正整数 n n n 有 m m m 个不同的素数因子 p 1 , p 2 , ⋅ ⋅ ⋅ , p m p_1,p_2,···,p_m p1,p2,⋅⋅⋅,pm,则可以表示为: n = p 1 t 1 × p 2 t 2 × ⋅ ⋅ ⋅ × p m t m n={p_1}^{t_1}×{p_2}^{t_2}×···×{p_m}^{t_m} n=p1t1×p2t2×⋅⋅⋅×pmtm。
小 P 认为,每个素因子对应的指数 t i t_i ti 反映了该素因子对于 n n n 的重要程度。现设定一个阈值 k k k ,如果某个素因子 p i p_i pi 对应的指数 t i t_i ti 小于 k k k ,则认为该素因子不重要,可以将 p i t i {p_i}^{t_i} piti 项从 n n n 中除去;反之则将 p i t i {p_i}^{t_i} piti 项保留。最终剩余项的乘积就是 n n n 简化后的值,如果没有剩余项则认为简化后的值等于 1 1 1。
试编写程序处理 q q q 个查询:
从标准输入读入数据。
输入共 q + 1 q+1 q+1 行。
输入的第一行包含一个正整数 q q q,表示查询的个数。
接下来 q q q 行每行包含两个正整数 n n n 和 k k k,表示一个查询。
输出到标准输出。
输出共 q q q 行。
每行输出一个正整数,表示对应的查询结果。
3
2155895064 3
2 2
10000000000 10
2238728
1
10000000000
查询一:
查询二:
查询三:
40%的测试数据满足: n ≤ 1000 n \leq 1000 n≤1000;
80%的测试数据满足: n ≤ 1 0 5 n \leq 10^5 n≤105;
全部的测试数据满足: 1 < n ≤ 1 0 10 1 < n \leq 10^{10} 1<n≤1010 且 1 < k 1 < k 1<k, q ≤ 10 q \leq 10 q≤10。
#include
using namespace std;
bool domains[100000001]; //domains布尔数组,用于标记数字是否为素数
int prime[100000001], tot; //prime整用于存储素数,tot用于记录素数的个数
void sieve(int n){ //筛法(Sieve)计算素数个数
for(int i = 2; i*i <= n; i++){ //筛法重要思想:从2开始,遍历到不大于n的平方根即可
/*
对于大规模数组,适用于筛法求解,即for(int i=2; i*i<=n; i++)
对于小规模数组,不适用于筛法求解,可用for(int i=2; i <=n; i++)
*/
if(domains[i] == false){ //如果domains[i]为 false,则表示i是素数,从素数2开始遍历,默认初始为false
prime[++tot] = i ; //如果i是素数,将 i 添加到素数数组prime中,并且素数数量tot加一
for(int j = i; i*j <= n; j++) //对遍历到的每一个i,标记i的倍数必定不是素数
domains[i*j] = true; //如果i是素数,将domains[i*j]设置为 true
}
}
return;
}
int main()
{
sieve(100000001); //首先利用筛法找出所有的素数
int q, k;
long long n; //注意这里的正整数n可能很大
cin >> q; //输入要处理的q个查询
for(int i = 0; i < q;i++){
cin >> n >> k; //输入每个查询中的正整数n及阈值k
long long result = 1, power = 0, temp = 1; //result表示最终结果,power表示素数的幂,temp表示中间素数乘积的结果
for(int i = 1; i <= tot; i++) //注意tot是从1开始计数的,所以这里只能从i=1开始遍历所有素数
{
power = 0, temp = 1; //每次循环还是前将幂和中间结果乘积重置,这表示对每一个素数单独处理计算,这一点很重要!!!
while(n % prime[i] == 0) //因为要把正整数n分解为众多素数的乘积,所以n是素数的整数倍时进入循环
{
n = n / prime[i]; //更新除以该因数素数之后的n,也即因式分解过程
temp = temp * prime[i]; //更新该因数素数出现所有次数后的乘积,也即因式合成过程
power++; //该因数素数的幂加一
}
if(power >= k) //如果当前素数prime[i]的出现次数(幂值)power大于等于阈值k
result = result * temp; //最终结果累乘间素数乘积的结果
}
cout << result << endl;
}
return 0;
}
'''
代码逻辑与C++完全相同,不再一一逐行赘述
'''
import numpy as np
# 使用NumPy数组代替列表,并使用NumPy提供的函数处理筛选素数的过程
def sieve(n):
domains = np.zeros(n+1, dtype=bool)
prime = []
for i in range(2, int(np.sqrt(n))+1):
if not domains[i]:
prime.append(i)
domains[i*i:n+1:i] = True
return prime
q = int(input())
primes = sieve(100000001)
for _ in range(q):
n, k = map(int, input().split())
result = 1
for p in primes:
power = 0
while n % p == 0:
n //= p
power += 1
if power >= k:
result *= p ** power
print(result)
本题代码可以用于解决以下问题: