因子化简(Python)
本题解参考自:CCF-CSP 202312-2 因子化简(Java、C++、Python)_因子化简问题-CSDN博客
一、前置知识(质数筛选)
-
质数就是除了1和它本身没有其他因数的数。根据定义,判断一个数n是不是质数,我们要遍历[2,n-1],如果它不能被这些数中的任何一个整除,那它就是一个质数。这样做的时间复杂度是O(n),我们要筛n-2个数,才能确定一个数是质数。有没有方法优化它呢?有。根据数学定义,我们可以把遍历的范围从[2,n-1]缩小到[2,
],这样,时间复杂度就变成
。这个是比较常见的思路。
-
上面的方法是比较常见的,即给定一个数,让你求这个数是不是质数。但如果给定一个数,让你求从1到这个数的所有自然数是不是质数呢?(问题1)这个时候时间复杂度就很大了。我们需要继续缩小筛选范围,让需要筛查的数字变少,这样时间复杂度就降下来了。怎么做呢?我们其实可以只筛查[2,
]的所有质数(因为你在求解问题1的时候,肯定是从小到大找质数的,那比你当前正在检测的这个数小的哪些质数就都已经被找出了,可以利用)。这个结论的原理在此不作证明。这个其实就是埃式筛。
-
还有一种方法叫线性筛。道理其实也一样,就是让需要筛查的数变少,这样时间复杂度就降下来了。说到底就是数学前置知识,知道了就好,算法就更快。
以上参考自:算法篇——素数筛-CSDN博客
二、问题
三、分析
第一步,根据问题,我们要做一张质数表。所以我们要利用前置知识的第二点。题目给的数字范围是在[1,1的10次方]。质数最大也就是[1,1的5次方],我们只要做出这个范围内的质数表。
max_val = 100000
primes = [] #质数表
for i in range(2,max_val):
#判断当前数是不是质数
if all(i%p!=0 for p in primes if p*p<=i):
primes.append(i)
第二步,分解质因数。我们设立一个长度为max_val的空列表cnt,索引代表质因数,值代表质因数的次数。题目还要求我们如果找不到质因数,就默认答案是1,针对这一点,我们可以设立变量ans,初始时ans=n(n即给出的要分解的数)。原来的数n会被不断地除,直到等于1。我们在除完n之后,设置ans // = n。此时,如果一开始的n不能被分解,那么n就是还是n,ans //= n后ans会变成1,就可以满足题目的要求了。
四、完整代码
def factorSimpliying(q,Q,primes):
max_val=100000
for i in range(q):
n,k=Q[i][0],Q[i][1]
ans=n
cnt=[0] * max_val
for prime in primes:
while n % prime == 0:
n //= prime
cnt[prime] +=1
ans //= n
for prime,t in enumerate(cnt):
if t<k and t!=0:
ans //= pow(prime,t)
print(ans)
#1 输入
q = int(input())
Q = [list(map(int, input().split())) for _ in range(q)]
# 找质数
max_val=100000 #因为最大的数是10的10此方,所以它的质数最大是10的5次方
primes = []
for i in range(2,max_val):
#判断当前i是不是质数
if all(i%p!=0 for p in primes if p * p <= i):
primes.append(i)
#2 输出
factorSimpliying(q,Q,primes)