链接:
https://www.nowcoder.com/acm/contest/82/A
来源:牛客网
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
t次询问,每次给你一个数n,求在[1,n]内约数个数最多的数的约数个数
输入描述:
第一行一个正整数t 之后t行,每行一个正整数n
输出描述:
输出t行,每行一个整数,表示答案
分析:
1)约数个数定理:
对于一个大于1的正整数n可以分解质因数:
则n的正约数个数是:
p1,p2,p3……是质数
2)对于12=2^2*3,18=2*3^2,可见约数个数相同的数,质数的指数大的约靠前,我们越能得到较小的数,所以给指数一个上限,(根据题目2^q不超过最大n值即可),让下一个素数的指数小于这个素数的指数。
3)代码中的num表示1-n中约数最多的数。
if(t>maxn||(t==maxn&&m<num)){
num=m;
maxn=t;
}
t表示当前数的约数个数,maxn表示最大的约数个数,m表示的是当前的数,可见,当t>max时或等于且m<num值时,我们另num=m,maxn=t;也就是说当约数个数相同的时候,我们求的是较小的那个数(当然这道题没让求num)
代码如下:
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
int a[20]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,51};
ll n,num,maxn;//maxn表示1-n内最大的约数个数,num表示最大约数的数
void dfs(ll m,ll f,ll t,ll pr){//m当前值,f当前素数,t约数个数,pr质数限制
if(t>maxn||(t==maxn&&m<num)){
num=m;
maxn=t;
}
ll z=1,yg,now=m;//z当前素数的指数,yg约数个数,now记录当前值的变化
while(z<=pr){
z++;
if(n/a[f]<now){//这种情况不能再乘p[f]这个素数了
break;
}
yg=t*z;//约数的个数=当前约数的个数*素数的指数加1(z每次都先+1了)
now=now*a[f];
dfs(now,f+1,yg,z-1);//下一个素数的指数要小于这个素数的指数所以z-1
}
}
int main(){
int t;
scanf("%d",&t);
while(t--){
num=-1,maxn=-1;
scanf("%lld",&n);
dfs(1,1,1,64);
printf("%lld\n",maxn);
}
}