求1~N 的数中因子是最多的数及其最多的个数

博客围绕求1~N当中约数个数最多的数的个数展开。输入为T组数据,每组含一个数N。直接暴力求解会超时,依据唯一分解定理拆分因子也会超时。通过举例说明可在枚举时优化,使2的指数不小于3的指数等,以得到质因数分解“模式”相同的最小数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【问题描述】

求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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值