幂运算转換
幂运算转換
(现将个整数的需运算,转换为质数的乘运算,质数按从小到大排序。
质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
解答要求
限制:C/C++ 1000ms,
其他语言:2000ms
输入
整数的幂运算连乘表达式,表达式中只有乘和幂运算,其中*表示乘运算,^表示幂运算
整数的范围:[1,100000]指数范围:[1,100]
输入为一个合法的表这式,表达式最长为1000个字符。
输出
转换为质数的乘运算,质数按从小到大排序。
保证输出最长不超过100000.
输入: 6^3*10
输出: 2*2*2*2*3*3*3*5
解释:6^3*10
6*3可以拆分为质数乘(2"3)^3,进一步表示为2"2*2*3*3*310可以拆分为质数乘2*5
输入: 5*14
输出:2*5*7
请用python stdin stdout解本题
code
import sys
import math
from collections import defaultdict
def sieve_spf(max_num):
"""Sieve of Eratosthenes to compute smallest prime factor (spf) for each number up to max_num."""
spf = [0] * (max_num + 1)# spf 数组用于存储每个数字的最小质因数,初始化为0(表示未计算)。
spf[0], spf[1] = 0, 1
for i in range(2, max_num + 1):
# 遍历从2到max_num的每个数字,如果一个数字的最小质因数尚未计算(即spf[i] == 0),
# 则将其最小质因数设为它自己,并更新所有该数字的倍数的最小质因数。
if spf[i] == 0:
spf[i] = i
for j in range(i * i, max_num + 1, i):# 更新所有该数字的倍数的最小质因数
if spf[j] == 0:# 只有当spf[j]==0的时候才更新
spf[j] = i
return spf
def factorize(x, spf):
"""Factorize x using the precomputed spf table. Returns a list of prime factors."""
# 使用预先计算好的spf表来分解一个数x,返回一个包含x所有质因数的列表。
# 通过不断地除以x的最小质因数来分解x,直到x变为1。
factors = []
while x > 1:
factors.append(spf[x])
x //= spf[x]
return factors
def main():
# input_expr = sys.stdin.read().strip()
input_expr = input("please input your expression:").strip()
if not input_expr:
print("")
sys.exit(0)
# Precompute SPF up to 100,000
MAX_NUM = 100000
spf = sieve_spf(MAX_NUM)
# Split the expression by '*'
terms = input_expr.split('*')
prime_counts = defaultdict(int) # 统计每个质因数出现的次数
for term in terms:
if '^' in term:
base_str, exp_str = term.split('^')
base = int(base_str)
exponent = int(exp_str)
else:
base = int(term)
exponent = 1
if base == 1:
continue # 1 has no prime factors
factors = factorize(base, spf)
for prime in factors:
prime_counts[prime] += exponent # 2^3 也就是2会出现3次
if not prime_counts:
print("")
sys.exit(0)
# Collect primes in sorted order
sorted_primes = sorted(prime_counts.keys()) # 按字典的key进行排序
# Build the output list
output = []
for prime in sorted_primes:
count = prime_counts[prime]
output.extend([str(prime)] * count)
# Join with '*'
print('*'.join(output))
if __name__ == "__main__":
main()
这段代码是埃拉托斯特尼筛法(Sieve of Eratosthenes)的一个变种,用于计算每个数字的最小质因数(smallest prime factor, SPF)。我将详细解释这段代码的逻辑:
-
外层循环:
for i in range(2, max_num + 1)
:从2开始遍历到max_num
。这个循环用于找到每个数字的最小质因数。
-
内层循环:
for j in range(i * i, max_num + 1, i)
:这个循环从i * i
开始,到max_num + 1
结束,步长为i
。这个循环的目的是更新所有i
的倍数的最小质因数。
-
更新最小质因数:
if spf[j] == 0
:检查j
的最小质因数是否已经计算过。如果spf[j]
为0,表示j
的最小质因数尚未计算。spf[j] = i
:将j
的最小质因数设为i
。
详细解释:
-
为什么从
i * i
开始:- 当我们找到一个质数
i
时,所有小于i * i
的i
的倍数(如2*i
,3*i
, …,(i-1)*i
)在之前的步骤中已经被处理过了,因为它们的最小质因数是小于i
的质数。因此,我们从i * i
开始,因为这是第一个可能的i
的倍数,其最小质因数是i
。
- 当我们找到一个质数
-
为什么步长为
i
:- 我们需要更新所有
i
的倍数的最小质因数,因此每次增加i
,即i * i, i * (i + 1), i * (i + 2), ...
。
- 我们需要更新所有
-
为什么只更新
spf[j]
为0的情况:- 如果
spf[j]
已经不为0,说明j
的最小质因数已经被计算过,我们不需要再次更新它。只有当spf[j]
为0时,我们才将j
的最小质因数设为i
。
- 如果
例子:
假设max_num = 10
,我们来逐步计算spf
数组:
-
初始化:
spf = [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
-
i = 2:
spf[2] = 2
- 更新
j = 4, 6, 8, 10
:spf[4] = 2
spf[6] = 2
spf[8] = 2
spf[10] = 2
spf = [0, 1, 2, 0, 2, 0, 2, 0, 2, 0, 2]
-
i = 3:
spf[3] = 3
- 更新
j = 9
:spf[9] = 3
spf = [0, 1, 2, 3, 2, 0, 2, 0, 2, 0, 2]
-
i = 4:
spf[4]
已经为2,跳过。
-
i = 5:
spf[5] = 5
spf = [0, 1, 2, 3, 2, 5, 2, 0, 2, 0, 2]
-
i = 6:
spf[6]
已经为2,跳过。
-
i = 7:
spf[7] = 7
spf = [0, 1, 2, 3, 2, 5, 2, 7, 2, 0, 2]
-
i = 8:
spf[8]
已经为2,跳过。
-
i = 9:
spf[9]
已经为3,跳过。
-
i = 10:
spf[10]
已经为2,跳过。
最终,spf
数组为:
[ [0, 1, 2, 3, 2, 5, 2, 7, 2, 3, 2]]
这个数组表示每个数字的最小质因数。例如,spf[10] = 2
表示10的最小质因数是2。