zoukankan      html  css  js  c++  java
  • 求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); } }
  • 相关阅读:
    uva 10369 Arctic Network
    uvalive 5834 Genghis Khan The Conqueror
    uvalive 4848 Tour Belt
    uvalive 4960 Sensor Network
    codeforces 798c Mike And Gcd Problem
    codeforces 796c Bank Hacking
    codeforces 768c Jon Snow And His Favourite Number
    hdu 1114 Piggy-Bank
    poj 1276 Cash Machine
    bzoj 2423 最长公共子序列
  • 原文地址:https://www.cnblogs.com/acSzz/p/2606079.html
Copyright © 2011-2022 走看看