首页 > 代码库 > [BZOJ 1053] Anti-prime

[BZOJ 1053] Anti-prime

题意

  记 $g(x)$ 为 $x$ 的约数个数.

  定义 Anti-prime : 对于 $x \in \mathbb{Z} ^ +$ , 若 $\forall i \in (0, x)$ , $g(x) > g(i)$ , 则称 $x$ 为一个 Anti-prime .

  给定一个数 $N(N \le 2 \times {10} ^ 9)$ , 求 $\max_{x \le N, x 是 Anti-prime}x$ .

 

分析

  我们尝试找到 Anti-prime 的一些性质, 以更好地求解这个问题.

 

  Anti-prime 与约数个数有关, 我们尝试利用唯一分解, 来进行分析.

  设一个 Anti-prime $x = \prod_{k = 1} ^ m {a_k} ^ {p_k}$ .

  不妨令 $a_1 < a_2 < ... < a_m$ .

  基本地, 有 $g(x) = \prod_{k = 1} ^ m (p_k + 1)$ .

 

  我们发现, 经过了唯一分解之后, 我们有两类量 $\left\{ a_1, a_2, ..., a_m \right\}$ 和 $\left\{ p_1, p_2, ..., p_m \right\}$ .

  直接探究没有任何的结果, 我们尝试控制变量.

 

  当 $p_1, p_2, ..., p_m$ 一定, 考虑 $a_1, a_2, ..., a_m$ 要满足什么条件.

  此时 $g(x)$ 已经确定为 $\prod_{k = 1} ^ m (p_k + 1)$ .

  根据 Anti-prime 的定义, $\forall y < x, g(y) < g(x)$ , 所以 $x$ 应该是指数为 $p_1, p_2, ..., p_m$ 的最小的数.

  所以要求 $a_1, a_2, ..., a_m$ 取前 $m$ 个素数.

  而注意到 $N \le 2 \times {10} ^ 9$ , 也就是说只会利用到前面的 $10$ 个素数.

 

  当我们取了前 $m$ 个素数 $2, 3, 5, 7, 11, ...$ 的时候, 考虑 $p_1, p_2, ..., p_m$ 要满足什么条件.

  我们一定有 $p_1 \ge p_2 \ge p_3 \ge ... \ge p_m$ , 否则可以通过交换, 构造更小且约数个数相同的数.

 

  总之, 我们得到了两个 Anti-prime 的性质:

    ① $a_1, a_2, ..., a_m$ 取前 $m$ 个素数.

    ② $p_1 \ge p_2 \ge ... \ge p_m$ .

 

  现在考虑求解问题.

  $$\begin{aligned} 一个数 x 是 N 以内最大的 Anti-Prime & \Leftrightarrow \forall y > x, g(y) \le g(x) , \forall y < x, g(y) < g(x) \\ & \Leftrightarrow x 是 N 以内约数个数最大的最小的数 \end{aligned}$$ .

  我们利用之前探究出来的两个性质, 暴力地进行枚举, 然后取约数个数最大的最小的数即可. 

 

实现

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
using namespace std;

#define LL long long

const int p[10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};

LL n;
LL D, N;

void Search(int dep, int lim, LL div, LL num) {
    if (dep == 10) {
        if (div > D || (div == D && num < N))
            D = div, N = num;
        return;
    }
    LL M = 1;
    for (int i = 0; i <= lim && num * M <= n; i++) {
        Search(dep+1, i, div * (i+1), num * M);
        M *= p[dep];
    }
}

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("bzoj1053.in", "r", stdin);
        freopen("bzoj1053.out", "w", stdout);
    #endif
    
    scanf("%lld", &n);
    Search(0, 35, 1, 1);
    printf("%lld\n", N);
    
    return 0;
}

 

[BZOJ 1053] Anti-prime