最多约数问题答案解析与勘误

问题描述: 
正整数x的约数是能整除x的正整数。正整数x 的约数个数记为div(x)。例如,1,2,5,10 都是正整数10 的约数,且div(10)=4。设a 和b 是2 个正整数,a≤b,找出a和b之间约数个数最多的数x。 
编程任务: 
对于给定的2个正整数a≤b,编程计算a 和 b 之间约数个数最多的数。 
数据输入: 
输入数据由文件名为input.txt的文本文件提供。文件的第1 行有2 个正整数 a和 b。 
结果输出: 
程序运行结束时,找到a 和b之间约数个数最多的那个数及最多约数个数。

测试数据:【只给出最多约数个数, time limit: 1s】



问题分析

下面的解析摘自网上一篇博客(来源http://blog.csdn.net/sarah_jieyu/article/details/6512030),标红部分是我自己添加上去的。

本题的要求是,求出一个给定区间内的含约数最多的整数。
    首先明确一下如何求一个数的约数个数:若一个数N满足:N = A1 N1 * A2 N2 * A3 N3 * …… * Am Nm,则n的约数个数为(N1 + 1) (N2 + 1) (N3 + 1) …… (Nm + 1)。这是可以用乘法原理证明的。
    最浅显的算法是,枚举区间内的每个整数,统计它们的约数个数。这个算法很容易实现,但是时间复杂度却相当高。因为题目约定区间的最大宽度可以达到10^9的数量级,相当庞大。因此,在极限规模时,时间是无法忍受的。所以,我们需要尽量的优化时间。
    分析一下枚举的过程就会发现,如果我们枚举到两个数n和m*n(m为一相对于n较大的质数),那么我们将重复计算n的约数两次。据此,我们发现了枚举效率低的根本所在。为了解决这一重复,我们可以选取另一种搜索方法——以质因子为对象进行深度搜索。
    初始时,令number := 1,然后从最小的质数2开始枚举,枚举包含一个2、两个2……n个2的情况……直至number * 2 n大于区间的上限(max)。对于每种“2^k的情况”,令number := number * 2 n,再枚举3的情况,然后,枚举5的情况、7的情况……方法相同。整个过程是一个深度搜索的过程。当number大于等于区间下限(min)时,我们就找到了一个区间内的数,根据前面介绍的方法,可以得到它的约数个数。所有的区间内的数的约数个数的最大值就是我们要求的目标。
    为什么这种深度搜索可以减少常规枚举过程中的重复问题呢?请看下面的一个例子
     设给定的区间为[6,30],6,18,30为区间内的数,按照常规枚举方法,计算18,30,的时候分别计算了因子6的约数个数,重复计算2次。如果使用上述所说的深度搜索方法,求这3个数的因数个数的路径有一条公共部分,2*3,这一部分只计算了一次,求18只需再乘个3,求30只需再乘个5,相对于常规枚举减少了两次计算2*3的时间。但这种深度搜索也有问题,就是number有可能是无用的,下面的分析便是对这种深搜方法进行无用数据剪枝。
    值得注意的是,我们枚举过程中得到的number可能无用的,即无论用number去乘以多少,都无法得到区间内的数。这样的number如果继续枚举下去,无疑会大大降低效率。那么,能否通过简单的判断,将其剪去呢?答案是可以的。很容易证明,如果(min – 1) div number < max div number,则区间内存在可以被number整除的数。因为,如果区间[min, max]内存在可以被number整除的数,也即是从min到max中至少有一个数能被number整除,那么区间[min – 1, max]内的数被number除得的商肯定不止一种,所以(min – 1) div number必然小于max div number。
反过来,如果(min-1)div number=max div number,则[min,max]内不存在可以被number整除的数。
证明如下:
  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值