首页 > 代码库 > [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