题目概述
g(x)=x的因子数,如果g(x)>g(i)(1<=i<=x-1),那么称x是反素数,求<=n的最大反素数。
解题报告
直接枚举肯定要炸掉的,我们需要寻找满足(或不满足)反素数的数的规律。写几个反素数看看:
4=22
6=21∗31
12=22∗31
24=23∗31
840=23∗31∗51∗71
我们发现反素数中小的素因子的个数总是不少于大的素因子的个数,这是巧合吗?我们试着证明一下:
设反素数n的标准分解为
pa11∗pa22∗pa33∗…∗pakk
,假设存在
ai<aj(i<j)
,那么一定存在一个数
m=pa11∗…∗paji∗…∗paij∗…pakk
,显然m的因子个数与n相同,且m<n,这与n是反素数矛盾,所以反素数中小的素因子的个数总是不少于大的素因子的个数得证。
由于要满足上述性质才是反素数,所以我们需要考虑的最大的素因子仅为29(2*3*5*7*11*13*17*19*23*29>2000000000)。也就是说我们可以直接枚举每个素因子的个数,这样的开销是非常小的!但是需要注意这么枚举只能减少枚举个数,不能确保枚举的均为反素数,也就是说我们枚举出来的是伪反素数(但肯定会枚举到所有反素数)。怎么从伪反素数中筛选出最大的反素数呢?其实很容易,因为我们肯定会枚举到所有反素数,所以从所有伪反素数中刷出因子数最大的数(因子数= ∏∞i=1(ai+1) ),再从因子数最大的数中刷出最小的即可。
示例程序
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXINT=((1<<30)-1)*2+1;
const int p[]={2,3,5,7,11,13,17,19,23,29};
int n,ans,num;
LL power(LL w,int b)
{
LL s=1;
while (b)
{
if (b&1) s*=w;
b>>=1;
if (b) w*=w;
}
return s;
}
void Dfs(int st,LL now,int lst,int sum)
{
if (now>n) return;
if (sum>num||sum==num&&now<ans) ans=now,num=sum;
if (st>9) return;
int ti=log(n/now)/log(p[st]);ti++;
for (int i=min(lst,ti);i>=0;i--)
Dfs(st+1,now*power(p[st],i),i,sum*(i+1));
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
scanf("%d",&n);
Dfs(0,1,MAXINT,1);
printf("%d\n",ans);
return 0;
}