【数学分析+DFS】BZOJ1053(HAOI2007)[反素数ant]题解

题目概述

g(x)=x的因子数,如果g(x)>g(i)(1<=i<=x-1),那么称x是反素数,求<=n的最大反素数。

解题报告

直接枚举肯定要炸掉的,我们需要寻找满足(或不满足)反素数的数的规律。写几个反素数看看:
4=22
6=2131
12=2231
24=2331
840=23315171
我们发现反素数中小的素因子的个数总是不少于大的素因子的个数,这是巧合吗?我们试着证明一下:
设反素数n的标准分解为 pa11pa22pa33pakk ,假设存在 ai<aj(i<j) ,那么一定存在一个数 m=pa11pajipaijpakk ,显然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;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值