求1~N 的数中因子是最多的数

求1~N当中约数个数最多的数”问题的优化
2010-04-13 20:56

【问题描述】

求1~N当中约数个数最多的数,若有多解则输出最小的数。

【输入格式】

输入文件只有一行。这一行有一个数N(1≤N<10^17)。

【输出格式】

输出文件只有一行。这一行有一个数,即所求的数。

【输入样例】

2000

【输出样例】

1680

题目分析:

(1)此题最容易想到的是穷举,但是肯定超时。

(2)我们可以知道,计算约数的个数和质因数分解有着很大的联系:

若Q的质因数分解为:Q=p1^k1*p2^k2*…*pm^km(p1…pm为素数,k1…km≥1),则Q有(k1+1)(k2+1)…(km+1)个约数。

但是质因数分解的时间复杂度很高,所以也会超时。

(3)通过以上的公式,我们可以“突发奇想”:为何不能把质因数分解的过程反过来呢?

这个算法就是枚举每一个素数。初始时让m=1,然后从最小的素数2开始枚举,枚举因子中包含0个2、1个2、2个2…k个2,直至m*2^k大于区间的上限N。在这个基础上枚举3、5、7……的情况,算出现在已经得到的m的约数个数,同时与原有的记录进行比较和替换。直至所有的情况都被判定过了。

这个算法的优化:如果p1*p2*p3*……*pk>N(pi表示第i个素数),那么只要枚举到p k-1,既不浪费时间,也不会遗漏。

根据以上的算法,对于上限需要枚举436555171个数,也会超时,不过可以过70-80%的数据。

(4)以上的算法还不是最好的,还可以继续优化。

我们看以下的例子:

6=2*3 10=2*5

6和10的质因数分解“模式”完全相同,所以它们的约数个数是相同的。但是由于3<5,所以6<10。

12=2^2*3 18=3^2*2

12和18的质因数分解“模式”完全相同,所以它们的约数个数是相同的。但是由于12的质因数分解中2的指数大于3的指数,18的质因数分解中3的指数大于2的指数,所以12<18。

根据以上的举例,我们也可以对(3)中的算法进行一个改进:可以在枚举时进行一个优化,使得枚举到的数字中2的指数不小于3的指数,3的指数不小于5的指数……这样我们就能够得到质因数分解“模式”相同的最小数(证明略)。再对于每一个得到的数进行比较和记录。这个算法对于上限只需要枚举34136个数,几乎达到了极限。

参考程序:

const a:array[1..15]of integer=(2,3,5,7,11,13,17,19,23,29,31,37,41,43,47);
var n,num:qword;
max,j:longint;
s:string;
procedure shu(m:qword;f,t,x:longint); {m为当前的数,f为当前枚举的素数,t为当前数的约数个数,x为指数的限制}
var i:qword;
j,l,p:longint;
begin
if (t>max)or((t=max)and(m<num)) then begin num:=m;max:=t;end;
j:=0;l:=1;i:=m;
repeat
j:=j+1;l:=l+1;i:=i*a[f];p:=t*l;
if i<=n then shu(i,f+1,p,j);
until(i>n)or(j=x);
end;
begin
readln(s);
n:=0;for j:=1 to length(s)do n:=n*10+ord(s[j])-48; {输入}
max:=1;num:=1; {num为已得到的约数最多的数,max为num的约数







#include<stdio.h> #define inf 9999999 int p[20] = {0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,51}; long long max,n; long long num; void get(long long m,int f,int t,int pr)//m代表当前值,f当前的素数,t约数的个数,pr指数限制 { if(t>max||(t==max&&m<num)) { num=m; max=t; } int j=0,l=1,nt; long long i=m; while(j<pr) { j++; l++; if(n/i<p[f])break; nt=t*l;//约数的个数 i=i*p[f]; if(i<=n)get(i,f+1,nt,j);//为什么是 j,为了是 前一个素数的指数大于后一个素数的指数 } } int main() { int t; scanf("%d",&t);; while(t--) { max=-1; num=-1; scanf("%lld",&n); get(1,1,1,30); printf("%lld\n",num); } }
原文地址:https://www.cnblogs.com/acSzz/p/2606079.html