问题描述:
对于任何正整数x,起约数的个数记做g(x).例如g(1)=1,g(6)=4.
定义:如果某个正整数x满足:对于任意i(0<i<x),都有g(i)<g(x),则称x为反素数.
现在给一个N,求出不超过N的最大的反素数.
比如:输入1000 输出 840
思维过程:
求[1..N]中最大的反素数-->求约数最多的数
如果求约数的个数 756=2^2*3^3*7^1
(2+1)*(3+1)*(1+1)=24
基于上述结论,给出算法:按照质因数大小递增顺序搜索每一个质因子,枚举每一个质因子
为了剪枝:
性质一:一个反素数的质因子必然是从2开始连续的质数.
因为最多只需要10个素数构造:2,3,5,7,11,13,17,19,23,29
性质二:p=2^t1*3^t2*5^t3*7^t4.....必然t1>=t2>=t3>=....
View Code
1 typedef __int64 INT; 2 INT bestNum; //约数最多的数 3 INT bestSum; //约数最多的数的约数个数 4 const int M=1000; //反素数的个数 5 INT n=500000;//求n以内的所有的反素数 6 INT rprim[M][2]; 7 //2*3*5*7*11*13*17>n,所以只需考虑到17即可 8 INT prim[14]={2,3,5,7,11,13,17,19,23,29}; 9 10 //当前走到num这个数,接着用第k个素数,num的约数个数为sum, 11 //第k个素数的个数上限为limit 12 void getNum(INT num,INT k,INT sum,INT limit) { 13 if(num>n)return; 14 if(sum>bestSum){ 15 bestSum = sum; 16 bestNum = num; 17 }else if(sum == bestSum && num < bestNum){ //约数个数一样时,取小数 18 bestNum = num; 19 } 20 if(k>=7) return; //只需考虑到素数17,即prim[6] 21 22 for(INT i=1,p=1;i<=limit;i++){ //素数k取i个 23 p*=prim[k]; 24 getNum(num*p,k+1,sum*(i+1),i); 25 } 26 } 27 28 INT log2(INT n){ //求大于等于log2(n)的最小整数 29 INT i = 0; 30 INT p = 1; 31 while(p<n){ 32 p*=2; 33 i++; 34 } 35 return i; 36 } 37 38 int getrprim(){//反素数的个数 39 int i = 0; 40 while(n>0){ 41 bestNum = 1; 42 bestSum = 1; 43 getNum(1,0,1,log2(n)); 44 n = bestNum - 1; 45 rprim[i][0]=bestNum; 46 rprim[i][1]=bestSum; 47 i++; 48 } 49 return i; 50 }