题目描述

对于任何正整数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


【分析】
唯一分解定理+暴搜+剪枝
唯一分解定理可以计算约数个数,观察后发现最多用到前12个质数,然后枚举每个素数的次数。
剪枝:小素数的次数>大素数的次数答案更优


【代码】

//[SDOI]反素数 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
int p[20]={0,2,3,5,7,11,13,17,19,23,29,31,37};
ll pow[20][50],t;
int n,ans;
inline void dfs(int dep,int num,ll now,int last) //num:因子个数
{
int i,j,k;
if(now>n || dep>12) return;
if(now>ans && num>t) ans=now,t=num;
if(now<=ans && num>=t) ans=now,t=num;
fo(j,0,last)
{
if(num*(j+1)>n || !pow[dep][j]) break;
dfs(dep+1,num*(j+1),now*pow[dep][j],j);
}
}
int main()
{
int i,j;
scanf("%d",&n);
fo(i,1,12) pow[i][0]=1;
fo(i,1,12) //第i个质数的j次方
fo(j,1,36)
{
pow[i][j]=pow[i][j-1]*p[i];
if(pow[i][j]>n) break;
}
dfs(1,1,1,32);
printf("%d\n",ans);
return 0;
}