题目大意
如果一个大于等于$1$的正整数 ,满足所有小于$n$且大于等于$1$的所有正整数的约数个数都小于$n$的约数个数,则$n$是一个反素数。比如:$1$,$2$,$4$,$6$,它们都是反素数。
输入一个$n$($1 leqslant n leqslant 10^{9}$),请你计算不大于$n$的最大反素数。
题解
我们知道,对于任意一个正整数$a$,有
$$a = prod_{i = 1}^{k} p_{i}^{t_{i}}$$
(其中${ p_{i} }$为质数集合。)
则$a$的约数个数为$prod_{i = 1}^{k} (t_{i} + 1)$。
我们只需要搜索${ t_{i} }$即可。
显然暴搜会超时,我们要加一下优化:
首先,根据贪心容易得到对于${ t_{i} }$,有$t_{i} geqslant t_{i + 1}$($1 leqslant i < k$)。
为什么呢?其实我们可以举一个最简单的例子。
$4 = 2 imes 2$,$6 = 2 imes 3$。显然$4$和$6$的约数个数相等,但$4 < 6$,所以$4$是反素数,而$6$不是。
所以我们可以根据这个特性来剪枝。
然后。根据上面我们也可以在筛质数的时候减少枚举量,也就是说如果当前$prod_{i = 1}^{k} p_{i} > n$,那我们就不用求出大于$p_{k}$的质数了。(当然我们也可以直接打个质数表)。
#include <iostream> #include <cmath> #define MAX_SQRT_N 45000 using namespace std; int n; int p[MAX_SQRT_N], tot; bool f[MAX_SQRT_N]; int maxcnt, ans; void DFS(int idx, int cnt, int last, int num) { if(cnt > maxcnt || cnt == maxcnt && num < ans) { maxcnt = cnt; ans = num; } if(idx > tot || !last) return; for(int i = 0; i <= last; ++i) { DFS(idx + 1, cnt * (i + 1), i, num); if((long long)num * p[idx] > n) break; else num *= p[idx]; } return; } int main() { cin >> n; int tmp = 1; for(int i = 2; i <= n; ++i) { if(!f[i]) { if((long long)tmp * i > n) break; tmp *= i; p[++tot] = i; } for(int j = 1; (long long)i * p[j]<= n; ++j) { f[i * p[j]] = true; if(!(i % p[j])) break; } } DFS(1, 1, 31, 1); cout << ans; return 0; }