Antiprime数-数论

题目描述 Description

如果一个自然数n满足:所有小于它的自然数的约数个数都小于n的约数个数,则称n是一个Antiprime数。譬如:1、2、4、5、12、24都是Antiprime数。

 输入输出格式 Input/output
输入格式:
输入文件中只有一个整数n(1≤n≤2 000 000 000)。
输出格式:
输出文件中也只包含一个整数,即不大于n的最大Antiprime数。
 输入输出样例 Sample input/output
样例测试点#1

输入样例:

1000
输出样例:

840

思路:

  这个问题可以转化为求n以内约数最多的数,对于一个n,如果它的质因子越小,那么它能分解的因子个数也就越多,而对于有相同因子数的两个数,较小的那个更具有更新的空间,所以当两个数有相同因子数时,我们取较小一个。

  根据唯一分解定理,任何一个大于1的数都可以分解为许多质数的乘积,并且根据质因数的个数可以算出约数的个数,公式为:n=P1x+P2y+P3z+P,这个n的约数个数为(x+1)(y+1)(z+1)(…+1),那么这题,我们可以从1,从小到大循环,每次分解这个数为质因数,最终找到约数最多的数(约数相同取较少的,因为假如取较大的那个,因为较小的那个在前面,并且约数个数和较大的那个一样,这样就会出现较大的数不满足Antiprime数定义,所以我们取较小的数,这样前面就不会有数来和它冲突),输出即可。

  但这样会超时,我们不妨做一下优化,逆用唯一分解定理,从小到大枚举每个质因数的使用个数(由数据范围限定最多枚举到23),搜索答案。

  记住一定要用long long。

代码如下:

 1 #include<cstdio>  
 2 #include<cmath>    
 3 long long n,maxx,num[12]={0,2,3,5,7,11,13,17,19,21,23},ans;  
 4 void findd(long long now,long long tot,long long u,long long v)//当前累计值,当前累计因数个数,上个质因数使用次数,枚举位置 
 5 {  
 6     if(maxx<tot||(tot==maxx&&ans>now))  
 7     {  
 8         maxx=tot;
 9         ans=now;  
10     }  
11     if(v>=11) return;  
12     for(long long i=1;i<=u;i++)  
13     {  
14         now*=num[v];  
15         if(now>n) return;  
16         findd(now,tot*(1+i),i,v+1);  
17     }  
18 }   
19 int main()  
20 {   
21     scanf("%I64d",&n);  
22     findd(1,1,500,1);  
23     printf("%I64d\n",ans);  
24     return 0;  
25 }  

 

posted @ 2017-01-17 10:56  Memoryヾノ战心  阅读(1088)  评论(0编辑  收藏  举报