『学习笔记』蓝书 0x32 约数

定义

若整数 \(n\) 除以整数 \(d\) 的余数为 \(0\),即 \(d\) 能整除 \(n\),则称 \(d\)\(n\) 的约数,\(n\)\(d\) 的倍数,记为 \(d|n\)

\(p_i\) 为质数,\(c_i\) 为指数。

算术基本定理

对于任意大于 \(1\) 的正整数 \(N\),可写作 \(N=p_1^{c_1}p_2^{c_2}\cdots p_m^{c_m}(p_1<p_2<\cdots<p_m)\)

推论

\(N\) 的正约数集合可写作:\(\lbrace p_1^{b_1}p_2^{b_2}\cdots p_m^{b_m} \rbrace\),其中 \(0 \le b_i \le c_i\)

\(p_i\) 的指数 \(b_i\)\(c_i+1\) 种可能的取值,则 \(N\) 的正约数个数为

\[(c_1+1) \times (c_2+1) \times \cdots \times (c_m+1)=\prod\limits^m_{i=1}(c_i+1) \]

\(N\) 的所有正约数的和为

\[\begin{array}{c l} &p_1^0p_2^0\dots p_m^0+p_1^1p_2^0\dots p_m^0+\cdots+p_1^{c_1}p_2^{c_2}\dots p_m^{c_m}\\ =&(p_1^0+p_1^1+\dots+p_1^{c_1})\times\cdots\times(p_m^0+p_m^2+\dots+p_m^{c_m})\\ =&\prod\limits_{i=1}^m(\sum\limits_{j=0}^{c_i}p_i^j) \end{array} \]

求正约数集合

试除法

扫描 \(x=1\sim\sqrt N\),判断 \(x\) 是否整除 \(N\)。若能整除,则 \(x\)\(N/x\) 均为 \(N\) 的约束。时间复杂度 \(O(\sqrt N)\)

推论\(N\) 的约数个数上限为 \(2\sqrt N\)

倍数法

若求 \(1\sim N\) 每个数的正约数集合,使用倍数法。

类似筛法,对于正整数 \(x \in [1,N]\),则 \(x,2x,3x,\dots,\lfloor\dfrac{N}{d}\rfloor \times d\) 均含有约数 \(x\)

时间复杂度 \(O(N+\dfrac{N}{2}+\dfrac{N}{3}+\dots+\dfrac{N}{N})=O(N\log N)\)

推论\(1 \sim N\) 每个数的有约数个数总和约为 \(N\log N\)

P1463 反素数

正整数 \(x\) 约数个数记作 \(g(x)\),若 \(\forall 0<i<x,g(i)<g(x)\),则 \(x\) 为反质数。\(\text{e.g.}\ 1,2,4,6\)

给定 \(N\) 求不超过 \(N\) 的最大反质数。

思路

引理:

  1. \(1 \sim N\) 中最大反质数就是 \(1 \sim N\) 中约数个数最多的数中最小的一个。

  2. \(1 \sim N\) 中任意数的不同质因子都不会超过 \(10\) 个,且所有质因子指数总和不超过 \(30\)

    \(11\) 个质数乘积即 \(>2\times 10^9\),且 \(2^{31}>2\times10^9\)

  3. \(\forall x \in [1,N]\)\(x\) 为反质数,则 \(x=2^{c_1} \times 3^{c_2} \times \dots \times 29^{c_{10}}\),且 \(c_1 \ge c_2 \ge \dots \ge c_{10} \ge 0\)

    证明:

    若有正整数 \(a\),则对于 \(\forall m,n \in \mathbb{N_+},\forall k \in \mathbb{N}\)\(g(x \times m^k)=g(x \times n^k)=g(a) \times(k+1)\)

    由此,若反质数 \(x\) 存在 \(p_i<p_j,c_i<c_j\),则有 \(x/p_j^{c_j}\times p_i^{c_j}\) 约数个数与 \(x\) 相等,且比 \(x\) 更小。故此时 \(x\) 不是反质数。可得若反质数分解式中存在 \(p_i < p_j\),则必有 \(c_i \ge c_j\)。所以 \(c_i\) 单调不增。

综上,可以 dfs 出前 \(10\) 个质数的指数使其单调递减(引理 \(2,3\))且总乘积不超过 \(N\),按引理 \(1\) 更新答案。

#include <iostream>
using namespace std;
typedef long long ll;
const int inf=0x7fffffff;
int n,mxc,ans=inf;
int p[22]={0,2,3,5,7,11,13,17,19,23,29};

// id: 当前是第几个质数
// x: 用于判断是否为反质数,需小于 n
// cnt: x 的约数个数
// limit: 指数需满足条件
void dfs(int id,ll x,int cnt,int limit){
    if(id==11){
        if(cnt>mxc || cnt==mxc && x<ans)
            mxc=cnt,ans=x;
        return;
    }
    for(int i=0; i<=limit; i++){
        if(x>n) return;
        dfs(id+1,x,cnt*(i+1),i);
        x*=p[id];
    }
}

int main(){
    scanf("%d",&n);
    dfs(1,1,1,inf);
    printf("%d\n",ans);
    return 0;
}
posted @ 2025-01-05 21:49  仙山有茗  阅读(84)  评论(0)    收藏  举报