AcWing 198. 反素数【详解】
原题链接
中等
思路
- 求1-N中的反素数,实际上就是找出1-N中约数最多的数字,如果这个数字有 1个,取最小的一个。
- 记这个数字为x,可以分解质因数$x =p_1^{c_1}p_2^{c_2}....p_n^{c_n}$,且$p_1<p_2<…< p_n$。
- 由于$2 * 3 * 5 * 7 * 9 * 11 * 13 * 17 * 19 * 23 > 2^{31}-1 $,所以不同的质因子个数最多是9个,且$x$的质因子必定是从最小的9个质数里面选(反之则可以把任意一个质数替换成更小的质数,矛盾!),所以最多只有9个不同的选择,可以用dfs来写。
- 对于2中的表达式,对于任意$i>1$,有$c_{i-1}>c_i$。(若$c_{i-1} < c_{i}$,$p_{i-1}^{c_{i-1}}p_i^{c_i}$可以替换成$p_{i-1}^{c_i}p_i^{c_{i-1}}$,此时约数个数相同,但可以把x变成一个更小的一个数$y$,这与$x$是最小的数矛盾!)
- 综上所述,只需要利用最小的9个质数暴搜,外加第4部分析的剪枝就可以了
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
typedef long long LL;
using namespace std;
int n;
//最小的9个质数
int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23};
//maxd最大约数个数,number为这个数字
int maxd, number;
//u为p的下标,c是上一个质数的指数,p是当前的数字,s是当前数字的约数个数
void dfs(int u, int c, int p, int s) {
if(u == 9) return;
if(s > maxd || s == maxd && p < number) {
number = p;
maxd = s;
}
//依次选1-c个质数
for(int i = 1; i <= c; i++) {
if((LL)p * primes[u] > n) return;
p *= primes[u];
dfs(u + 1, i, p, s * (i + 1));
}
}
int main()
{
cin >> n;
dfs(0, log(n), 1, 1);
cout << number;
return 0;
}