反素数

背景
如果一个自然数比所有比它小的自然数的约数个数都要多,那么我们就称这个数为一个反素数。例如,1、2、4、6、12和24都是反素数。

任务
请写一个程序:
读入一个自然数n;
找出不大于n的最大的反素数;
将结果输出。

输入格式
只包含一行,为一个自然数n。

输出格式
输出唯一的一个整数——不大于n的最大反素数。


不那么暴力的暴力枚举还是很好搞的,看时间复杂度也不需要怎么优化,《进阶指南》上给了一大堆证明,可能以后涉及到有关反素数的内容还是会用到,所以还是摘录上来吧。以下均取自《进阶指南》P133-134。

细斜体是我自己YY的。

引理1:
1~N中最大的反素数,就是1~N中约数个数最多的数中最小的一个。

证明:
将任何正整数 x 的约数个数记作 g( x )。
设 m 是1~N中约数个数最多的数中最小的一个。根据 m 的定义,m 显然满足:
1.任意 x < m,g( x ) < g( m )
2.任意 x > m,g( x ) <= g( m )
根据反质数的定义,第一条性质说明 m 是反素数,第二条性质说明大于 m 的数都不是反素数,故 m 即为所求。

引理1用于更新答案。

引理2:
1~N中任何数的不同质因子不会超过10个,且所有质因子的指数总和不超过30。

证明:
这没什么好证的。不管是最小的11个质数的乘积还是只有最小质数2的20次方,都是大于题中 N 的。
这条可以用于边界处理。

引理3:
对于任意的 x 属于[ 1, N ],x 为反素数的必要条件是,x 分解质因数后可写作 a1^c1*a2^c2…*ak^ck,a是递增的质数序列且 ak<=29,c是单调递减的序列。

证明:
反证法。由引理2,若 x 的质因数分解式中存在一项 p^k (p>29),则必定有一个不超过29的质因子p’ 不能整除 x。根据算术基本定理的推论,x /( p^k ) * p’^k 的约数个数与 x 的约数个数相等,但前者更小,这与反素数定义矛盾。故 x 只包含29以内的质因子。
同理,若 x 的质因子不是连续若干个最小的①,或者指数不单调递减②,我们也可以通过上述交换质因子的方法,得到一个比 x 小、但是约数个数相等的整数,因此假设不成立,原命题成立。

①的证明和上面那段几乎一模一样,不重复了。至于②的证明,我不严密地感性证明了一下。
假设存在 x 的质因子 ci^ki 和 另一个质因子 cj^kj ,其中 ci < cj且 ki < kj,那么 x /( ( ci^ki ) * ( cj^kj ) ) * ( ci^kj )( cj^ki) 的约数个数与 x 相同,且前者更小,假设不成立。

终于敲完了。引理3给出了枚举的具体做法。我们可以从小到大枚举每个质数,由大到小枚举指数,越界 return 掉,基本就没问题了。搜索量很小。


code:

#include<bits/stdc++.h>
using namespace std;

int n;
long long ans=0LL;
int pri_[11]={0,2,3,5,7,11,13,17,19,23,29};
int c=0;

inline void read(int &x)
{
    x=0;int f=1;char s=getchar();
    for(;s<'0'||s>'9';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=(x<<3)+(x<<1)+s-48;
}

void dfs(long long now_,int sum_,int p,int k,int q)//当前,约数个数,指数和,已枚举质数,上一层指数。 
{
    if(k>10) return;
    if(sum_>c) ans=now_,c=sum_;
    if(sum_==c&&now_<ans) ans=now_;
    int tmp=1;
    for(int i=1;i<=q;++i)
    {   
        tmp*=pri_[k];
        if(tmp*now_>n) break;
        dfs(now_*tmp,sum_*(i+1),p+i,k+1,i);
    }
} 

int main()
{
    read(n);
    dfs(1LL,1,0,1,30);
    printf("%lld",ans);
    return 0;
}

当然还可以打表啦

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值