P1463 [HAOI2007]反素数

题目描述

对于任何正整数x,其约数的个数记作g(x)。例如g(1)=1、g(6)=4。

如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数。例如,整数1,2,4,6等都是反质数。

现在给定一个数N,你能求出不超过N的最大的反质数么?

输入输出格式

输入格式:

 

一个数N(1<=N<=2,000,000,000)。

 

输出格式:

 

不超过N的最大的反质数。

 

输入输出样例

输入样例#1: 复制

1000

输出样例#1: 复制

840

上课讲的一题,说是搜索+剪枝,一开始听不懂,很懵,上网找题解也看得有点不知所云,突然恍然大悟,我尽量表达地通俗易懂一些。

(1)首先想到直接暴力,但是如此就要找[1,n]的每一个数的因子个数,n<=2000000000,不用想肯定会爆。

(2)看了许多题解了解到几个性质

①对于某一个数,我们可以将其分解为质因子相乘的式子:2^k1*3^k2*5^k3……的形式(这个应该都懂)

然后这个数他的因子个数就是(k1+1)*(k2+1)*(k3+1)*(k4+1)……了

怎么去理解呢,我感性的理解就是,首先质数相乘出来的数肯定是唯一不会重复的,那么对于每一个质数就会尤其相对应的(k+1)的出现情况,那么每一个质因数不同的出现情况相乘,就是其因子的个数了,很好理解吧。

②如果这个数是一个反质数,那么他分解质因子后的式子一定满足k1>=k2>=k3……

这个怎么去看呢

首先由①可以知道如果k确定了(这里的k是k1,k2的集合),那么因子个数就确定了对吧,那么我们考虑这k1,k2……的排列,很明显,如果越大的ki给越小的质数,总体乘出来的数就是越小的。那么既然如此,其他比这个数大的数就肯定不满足反素数的性质了

 

好,有了上面的两个性质,就可以开始进行爆搜了,我来讲讲具体怎么搜,很多题解就是没说到,搞得我懵了好久。

如果不利用性质,我们就会暴力枚举每一个质因子的指数,然后看个数满不满足条件对吧,这样会超时

但是利用了这个性质,我们在枚举的时候,就要保证这个k的递减,那么爆搜的结果就极大地降低了。

!!!

注意:k递减得到的数也不一定是反素数,这也是为什么要爆搜的原因

n<=2*10^9所以只需枚举前十几个质数就ok,那个起始的最高指数,我是乱试的,感觉ok就行了。大了我也不知道为什么就得不出结果了,希望有大佬可以告诉我。

对于每一个爆搜得到的数,我要只需要记录出素数个数最多的那个数,这就是答案了, 因为答案肯定就包含在这些数中,如果它满足条件,那么因子个数肯定最多,我们就不需要考虑去验证它是不是反素数了。

附上代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int pri[11]={2,3,5,7,11,13,17,19,23,29,31},n,i; 
long long ans;
int ans2;
void find(int x,int z,int g,long long lei){
    if(lei > n)	return;
    if((g > ans2)||(g == ans2 && lei < ans)){
        ans=lei; ans2=g;	
    }
    long long c=1;
    for(int i=1;i <= z; i++){
        c*=pri[x];
        find(x+1,i,g*(i+1),lei*c);
    }
}
int main()
{
    scanf("%d",&n);
    ans=1;
    ans=1;
    find(0,23,1,1);
    printf("%lld",ans);
    return 0;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值