★★★ 输入文件: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分解质因数——>
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;
}