Python入门习题(48)——NOIP普及练习题:质因数分解

NOIP普及练习题:质因数分解


时间限制: 1000 Sec 内存限制: 128 MB

题目描述

已知正整数n是两个不同的质数的乘积,试求出两者中较大的那个质数。

输入
输入只有一行,包含一个正整数n。

输出
输出只有一行,包含一个正整数p,即较大的那个质数。

样例输入
21
样例输出
7

提示
【数据范围】
n <= 2*109

来源/分类
NOIP普及

解题思路

  1. 由于n的值达到10的9次方量级,因此以下做法是低效的,估计会超时。这一做法是:令p依次取3, 5, 7, 9, 11, 13, 15, …, n \sqrt{n} n ,看p和q(=n / p)是否符合要求。
  2. 假设p和q是一组解,有q=n/p,且有q > n,那么必有:p <= n \sqrt{n} n ,q>= n \sqrt{n} n
  3. 解题思路是:
    (1)从小到大地,利用筛选法找出 n \sqrt{n} n 内的全部质数p,存入prime_set。每找到一个质数p,如果n整除p,则把候选解 (p, q)追加到houxuan_list尾部,这里q = n / p。
    (2)从左到右遍历候选解列表houxuan_list,对于候选解(p, q),如果q是质数,那么q就是题目要求的结果。
    (3)如何判断q是否是质数?答案是,让q依次除以prime_set中的每个质数,如果整除某个质数,那么不是;都不能整除,那么是质数。
  4. 关于筛选法求质数(即素数)的做法,网上有大把的讲解,这里不予赘述。

参考答案

#num是质数吗
#prime_set里头保存了num的平方根内的全部素数
import math

def is_prime(num, prime_set):
    num_sqrt = int(math.sqrt(num))
    for p in prime_set:
        if num % p == 0:
            return False
    return True
#把i的奇数倍数(不大于n_sqrt)加入非质数集合not_prime_set
def add_not_prime_set(not_prime_set, i, n_sqrt):
    for m in range(3, n_sqrt + 1, 2):
        not_prime_set.add(m * i)

n = int(input())
if n % 2 == 0:
    print(n // 2)
else:
    n_sqrt = int(math.sqrt(n))
    #找出1到n_sqrt之间的质数和非质数
    not_prime_set = set()
    prime_set = set()
    houxuan_list = []  #保存候选解
    for i in range(3, n_sqrt + 1, 2):
        if i not in not_prime_set:
            prime_set.add(i)
            #把i的倍数加入not_prime_set
            add_not_prime_set(not_prime_set, i, n_sqrt)
            if n % i == 0:
                houxuan_list.append((i, n // i))

    for lessone, largerone in houxuan_list:
        if is_prime(largerone, prime_set):
            print(largerone)
            break

测试用例

  1. n是偶数的情形
    样例输入
    1994
    样例输出
    997

  2. n是奇数的情形。
    样例输入
    2991
    样例输出
    997

  3. n是奇数的情形。n稍大一点。结果不是997。
    样例输入
    8767
    样例输出
    797

小结

  1. 这道题要关注时间开销。对于n为109的量级的题目,只能采用线性级别(即时间开销为O(n))的算法。
  2. 筛选法求质数比较常用,值得熟练掌握。
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值