【搜索】【cogs 193】最多因子数

193. 最多因子数

★★★   输入文件:divisors.in   输出文件:divisors.out   简单对比
时间限制:3 s   内存限制:128 MB

【问题描述】

数学家们喜欢各种类型的有奇怪特性的数。例如,他们认为945是一个有趣的数,因为它是第一个所有约数之和大于本身的奇数。
为了帮助他们寻找有趣的数,你将写一个程序扫描一定范围内的数,并确定在此范围内约数个数最多的那个数。不幸的是,这个数和给定的范围的都比较大,用简单的方法寻找可能需要较多的运行时间。所以请确定你的算法能在几秒内完成最大范围内的扫描。

【输入格式】

只有一行,给出扫描的范围,由下界L和上界U确定,满足2≤L≤U≤1 000 000 000。

【输出格式】

对于给定的范围,输出该范围内约数个数D最多的数P。若有多个,则输出最小的那个。
请输出“Between L and U,P has a maximum of D divisors.”,其中L,U,P和D的含义同前
面所述。

【输入输出样例】
divisors.in

1000 2000

divisors.out

Between 1000 and 2000,1680 has a maximum of 40 divisors.

题解:

我们要对一段区间进行查询,很明显并不能一个一个去验证,时间会炸的飞起。
所以我们考虑对于一个数,它的约数个数是什么?
如果我们把一个数X分解质因数——>

X=2m13m25m3...nmk

通过乘法原理我们可以发现,它的约数个数是
(m1+1)(m2+1)(m3+1)...(mk+1)

于是我们可以从质因数来下手,因为它的范围是根号n的,然后对于每个质数进行扩展就好了。
网上有不错的文章,说的很详细,这里就不多说了,可以戳这里——> 对没错就是这里

Code:

#include
#include
#include
#include
#include
#include
#define N 100001
using namespace std;
int num=0,ans=0,minn,anx,yes[N],no[N];
void xs(){
    memset(yes,0,sizeof(yes));
    memset(no,0,sizeof(no));
    no[0]=no[1]=1;
    for (int i=2; iif (!no[i]) yes[num++]=i;
        for (int j=0; j*yes[j]no[i*yes[j]]=1;
            if (!(i%yes[j])) break;
        }
    }
}
void work(int start,int s,int x,int L,int R){
    if (x>=minn){
        if ((s>ans) || (s==ans && xs,anx=x;
    }
    if ((L==R) && (L>x))
        work(start,s<<1,x*L,1,1);
    for (int i=start; iif (yes[i]>R) return;
        int j=yes[i],ll=L-1,l=L,r=R,y=x,ss=s,m=1;
        while (1){
            m++; ss+=s; ll/=j; l/=j; r/=j;
            if (ll==r) break; y*=j;
            work(i+1,ss,y,l,r);
        }
        m=1<<m;
        if (s<(ans/m)) return;
    }
}
int main(){
    int l,r;
    scanf("%d%d",&l,&r);
    xs();
    if (l==1 && r==1) ans=1,anx=1;
    else {
        minn=l,ans=2,anx=l;
        work(0,1,1,l,r);
    }
    printf("Between %d and %d, %d has a maximum of %d divisors.\n",l,r,anx,ans);
    return 0;
}

你可能感兴趣的:(算法——搜索)