Luogu P1463 反素数

题目大意

  如果一个大于等于$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;
} 
参考程序
原文地址:https://www.cnblogs.com/kcn999/p/11270410.html