51nod 1060 最复杂的数 数学&dfs剪枝

题意:

给你一个数n,求1到n中因子最多的那个数,如果有多个这样因子相同的数,取数字最小的那个。

做法:

这个题首先要有前置技能,反素数。

我们通过打表每个数的因子个数可以发现:

数因子的数量在来回摆动,有波峰也有波谷,

而对于任意i<x,都有cnt[i]<cnt[x]的话,那么就把x叫做反素数。(cnt为因子个数)

反素数有两个性质:

no1: 一个反素数的质因子必然是从2开始的连续若干质数。

no2:x=2^a *3^b *5^c*7^d...(分解定理qwq,但是还有一个重要的限制,a>=b>=c>=d...)


有了前置技能后,我们考虑怎样写出来。

通过打表,我们可以发现2*3*5*7...*53(共16个)的乘积是大于1e18的,所以我们考虑16层循环太暴力了。

我们可以试试dfs

dfs参数首先有一个深度depth,控制到第几个数了,然后是precnt控制后面枚举的数的次数不超过前面的,这个可以大大的剪枝,

然后是num,说明这个数是多少,以及cnt这个数有多少因子。

其实这是我遇到的第一个把多重循环改成dfs的题,我的理解就是把dfs里的函数当作 for的一层来写,然后控制深度,其他并没有太大的差别。不过要注意传递的参数的选取,或者要不要考虑回溯。

代码如下:

#include<cstdio>
int p[16]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
const long long INF=1e18+7;
long long  n;
long long res,miniNum;
void dfs(int depth,int precnt,long long  num,long long  cnt)
{
    if(cnt>res)
    {
        res=cnt;
        miniNum=num;
    }
    if(res==cnt&&num<miniNum)miniNum=num;
    if(depth==16)return;
    for(int i=1;i<64&&i<=precnt;++i)
    {
        if(num<=n/p[depth])
        {
            num*=p[depth];
 //         printf("depth+1=%d,num=%lld,cnt*(i+1)=%lld\n",depth+1,num,cnt*(i+1));
            dfs(depth+1,i,num,cnt*(i+1));
        }
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld",&n);
        res=0,miniNum=INF;
        dfs(0,100,1,1);
        printf("%lld %lld\n",miniNum,res);
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值