【题意】
对于任何正整数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∗10^9
【输入样例】
1000
【输出样例】
840
分析
- 任何一个数都可以表示成若干素数的若干次方的乘积(即)
- 根据乘法原理可以得知,这个数的所有约数(不管是质约数还是合约数)的个数就是:
- 根据反素数的定义,1~N中最大的反质数,就是1~N中约数个数最多的数中最小的一个.因为,如果不是最小的那一个,必然会出现g(x)=g(i)
- 1~N中任何数的不同质因子都不会超过10个,因为2∗3∗5∗7∗11∗13∗17∗19∗23∗29∗31>2∗10^9
- 2∗3∗5∗7∗11∗13∗17∗19∗23∗29∗31>2∗10^9,且所有质因数的指数总和不超过30,因为2^31>2∗10^9
- x的质因子是连续的若干个最小的质数,且质数的指数单调递减.如果说我们选择的质数不是连续的,也就是A1∗A3那么我还不如选择A1∗A2因为这样数还更小.,如果说质数不是单调递减,c1<c2,那么那么C1跟C2交换会使得乘积更加小,而且约数个数不变(根据乘法的交换律可以得知)
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define INF 0xf0f0f0f
using namespace std;
typedef long long ll;
ll pri[21]={0,2,3,5,7,11,13,17,19,23,29};
inline ll read()
{
char c=getchar();ll s=0,f=1;
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){s=s*10+c-'0';c=getchar();}
return f*s;
}
ll n,tot[21];ll putout,ans;
inline void dfs(ll k,ll s,ll last,ll sum)
{
if(sum>ans || (sum==ans && s<putout))
{
ans=sum;
putout=s;
}
if(k>10 || last==0)return ;
ll get=1;
for(int i=0;i<=last;i++)//注意一定要从小到大,它不但可以防止爆炸,还可以节省时间
{
if(s*get>n)return;
tot[k]=i;
dfs(k+1,s*get,i,sum*(i+1));
tot[k]=0;
get*=pri[k];
}
}
int main()
{
n=read();
ans=0;
dfs(1,1,30,1);
printf("%lld\n",putout);
return 0;
}