对于任何正整数x,其约数的个数记作g(x),例如g(1)=1、g(6)=4。
如果某个正整数x满足:对于任意的小于x的正整数 i,都有g(x)>g(i) ,则称x为反素数。
例如,整数1,2,4,6等都是反素数。
现在给定一个数N,请求出不超过N的最大的反素数。
输入格式
一个正整数N。
输出格式
一个整数,表示不超过N的最大反素数。
数据范围
1≤N≤2∗109
输入样例:
1000
输出样例:
840
思路:根据反素数的定义:求一个数的约数个数比起小于它的数的约数个数都多的数,可以总结出判定1~n中最大反素数的两条性质:
1、约数个数最多
2、满足上一条性质的前提下,最小的数
因为一个数可以分解为其素因子之积的形式,即:p1^c1*p2^c2*...*pn^cn,
所以,其约数个数为:(c1+1)*(c2+1)*..*(cn+1)
约数之和为:(p1^0+p1^1+..p1^c1)*(p2^0+p2^1+..p2^c2)*...*(pn^0+pn^1+..pn^cn),(因为将该式展开每一项即为一个约数)
这里只用到了约数个数且用到的素数最大29就够了,因此只要dfs求1~n中出约数个数最多且最小的数即可,在dfs时,因为要使约数个数尽可能达到最多,所以越小的素因子的幂次一定尽可能多(分解成小的一定比分解成大的个数多),所以当前质因子的幂次一定小于等于上一个素因子的幂次,也就是说枚举每个素因子的幂次c时,从小到大枚举每个素因子并且素因子的幂次一定是呈递减趋势的,最后每个素因子的幂次+1的乘积((c1+1)*(c2+1)*..*(cn+1))即为当前方案的约数个数,取所有方案最大的个数即为答案。
完整代码:
#include
#include
#define int long long
using namespace std;
int primes[]={2,3,5,7,11,13,17,19,23,29};
int sum,res,n;
void dfs(int u,int lastmi,int num,int cnt)//u:当前素数,lastmi:上一个素数的幂次,num:当前素数乘积表示的反素数,cnt:当前反素数num的约数个数
{
if(cnt>sum||sum==cnt&&numn) break;
num*=p;
dfs(u+1,i,num,cnt*(i+1));
}
}
signed main()
{
cin>>n;
dfs(0,30,1,1);
cout<