【问题描述】
求1~N当中约数个数最多的数的个数。
【输入格式】 T组数据 每一组只有一行。这一行有一个数N(1≤N<10^18)。
simple input 3 13 9 1000000000000000000 simple output 13 9 103680 分析: 直接暴力肯定会超时,那么怎么处理呢???
根据唯一分解定理,我们可以知道一个整数是可以分解成素数的乘积的 那么就可以得到: 将任意自然数 n (n>2) 分解
n=p1k1p2k2p3k3…pmkm(p1<p2<⋯<pm)
则 n 的因子数为 (k1+1)(k2+1)…(km+1) 但是直接这样拆其因子也会引起超时的,那么就需要去剪枝优化,肯定会有小伙伴们会这样去想,枚举素因子的个数,先从最小的开始,然后选择0个p1,1个p1,2个p1……,然后再去找0个p2,1个p2,2个p2……,将这些遍历完之后去更新答案,不幸的是……………………这样去做还是会超时的(ಥ_ಥ)
是不是还可以再去优化剪枝呢,答案是对; 我们看以下的例子:
6=2 * 3 ;10=2*5
6和10的质因数分解“模式”完全相同,所以它们的约数个数是相同的。但是由于3<5,所以6<10。
12=22*3 18=32*2
个数都是一样的,问啥不去找最小的那一个呢,因此我们在求其个数的时候可以加一下限制条件,即: 可以在枚举时进行一个优化,使得枚举到的数字中2的指数不小于3的指数,3的指数不小于5的指数……这样我们就能够得到质因数分解“模式”相同的最小数
#include <iostream> #include <algorithm> #include <string> #include <map> #include <cstring> #include <cmath> #include <queue> #include <cstdio> #include <vector> #include <set> #include <stack> using namespace std; typedef long long ll; const int N = 1e6+10; const int INF=0x3f3f3f3f; const ll LINF=0x3f3f3f3f3f3f3f3f; const int MOD=1e9+7; #define rep(i,a,b) for(int i=a;i<=b;i++) #define Abs(x) ((x)>=0?(x):-(x)) ll n,ans; //假设给出的N是由连续相乘的素数得来的,那么最多存在当前这些素数的乘积 int prime[20] = {0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};//1--16 void dfs(ll m,ll res,int i,int limit){//m指当前的值,res代表因子个数,i代表当前需要乘的素因子是谁,limit是最多当前素因子能枚举的个数 ans=max(ans,res);//更新答案 ll cnt=1;//cut用于计当前素数的个数+1,因为是由上述的公式得到的; for(int j=1;j<=limit;j++) { cnt++; if(n/m<prime[i])//如果下一次再乘当前的素数会大于n的话就跳出,为啥不写成if(n<m*prime[i])呢? break;//因为有可能会越界,超出longlong,那么就会引起死循环或者爆栈 m*=prime[i]; if(m<=n) dfs(m,res*cnt,i+1,j); } } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif // ONLINE_JUDGE int T; scanf("%d",&T); while(T--){ scanf("%lld",&n); ans=0; dfs(1,1,1,61); printf("%lld\n",ans); } return 0; }