定义
反素数的定义:对于任何正整数n,其约数个数记为 f(n) f ( n ) ,例如 f(6)=4 f ( 6 ) = 4 ,如果某个正整数n满足:对任意的正整数 i(0<i<n) i ( 0 < i < n ) ,都有 f(i)<f(n) f ( i ) < f ( n ) ,那么称n为反素数。
性质
1.一个反素数的所有质因子必然是从2开始的连续若干个质数,因为反素数是保证约数个数为
x
x
的这个数 尽量小。
2.同样的道理,如果
n=2t1∗3t2∗5t3∗7t4∗...
n
=
2
t
1
∗
3
t
2
∗
5
t
3
∗
7
t
4
∗
.
.
.
,那么必有
t1≥t2≥t3≥t4≥...
t
1
≥
t
2
≥
t
3
≥
t
4
≥
.
.
.
常见问题
1.给定一个数n,求一个最小的正整数x,使得x的约数个数为n。
2.求出
1∼n
1
∼
n
中约数个数最多的这个数。
算法解析
基于它的性质我们可以建一颗搜索树,找到正解。比如
n=pa11∗pa22∗...∗pakk
n
=
p
1
a
1
∗
p
2
a
2
∗
.
.
.
∗
p
k
a
k
,以每一个
pi
p
i
为树的一层建立搜索树,深度为k。
以
12=22∗3
12
=
2
2
∗
3
为例进行说明,建树如下:
可以看出从根节点到每一个叶子结点这条路径上的所有数字乘起来都是12的约数,所以12有6个约数。
贴一份模板代码。
n的约数
#include <stdio.h>
#include <string.h>
#include <iostream>
#define LL long long
using namespace std ;
LL n,minnum,cnt ;
const int prime[20] = {1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47} ;
//num:当前枚举到的数,k:枚举到的第k大的质因子;cntt:该数的约数个数;maxxcnt:质因子个数上限;
void dfs(LL num,LL k,LL cntt,int maxxcnt)
{
if(k >= 16) return ;
//如果约数个数更多或者相同,将最优解更新为当前数;
if(cntt > cnt || (cntt == cnt && num < minnum))
{
cnt = cntt ;
minnum = num ;
}
LL temp = num ;
for(LL i = 1 ; i <= maxxcnt ; i++) //开始枚举每个质因子的个数;
{
if(temp > n / prime[k])
break ;
temp *= prime[k] ; //累乘到当前数;
dfs(temp,k+1,cntt*(i+1),i) ;
}
}
int main()
{
int T ;
scanf("%d",&T) ;
while(T--)
{
scanf("%lld",&n) ;
minnum = cnt = 1 ;
dfs(1,1,1,50) ;
printf("%lld\n",cnt) ;
}
return 0 ;
}