P1463 [POI2002][HAOI2007]反素数

Link

P1463 [POI2002][HAOI2007]反素数

Solve

不知道为什么这道题会变成省选的基础打表

通过分析题意,能得出三个引理

引理1

(1)$N$中的最大的反质数,就是$1$(N)中约数个数最多的数中最小的一个 。

引理2

1~N中任何的不同质因子都不会超过10个,且所有质因子的指数总和不超过30。

引理3

x的质因子是连续的若干个最小的质数,并且质数单调递增。

三个引理的证明就不给了,可以感性理解一下

综上所述,我们可以使用DFS尝试搜索前10个质数的指数,并满足指数递减、总乘积不超过N,同时记录约数的个数。
在这两个限制条件下,搜索量实际非常小,每当搜索出一个满足条件的整数的时候,我们就按照性质一的结论更新答案,最终得到约数个数最多的数中最小的一个。

Code

#include <algorithm>
#include <iostream>
#include <cstdio>
#define ll long long

using namespace std ;

int pri[15] = {0,2,3,5,7,11,13,17,19,23,29,31};
//最小的11个质数 
ll best = -1 , num = -1 ;
//万一答案是0呢? 
int n ;

void dfs(ll x  , int rest , int m, int up)
//x为当前数字的大小,m为当前数字约数的个数
//rest为当前质数的编号,up为小于三十的当前指数和
{
    if(m > best || (m == best && x < num))
        num = x , best = m ;
        //根据性质一的更新答案过程 
    ll ans = x ;
    int i = 0 ;
    while(i < up)
    {
        ++ i ;
        if(n / ans < pri[rest]) 
        //保证总乘积不超过N 
            return ;
        int kkk = m * (i + 1 ) ;
        ans *= pri[rest] ;
        if(ans <= n)
            dfs(ans , rest + 1 , kkk , i) ;
            //保证了质数的单调递减 
    }
    //加上这两个搜索的剪枝,就会感到dfs快的飞起  哈哈哈 
}

int main()
//及其卑微的主函数 
{
    scanf("%d" , &n) ;
    dfs(1 , 1 , 1 , 30);
    printf("%lld
" , num);
}
原文地址:https://www.cnblogs.com/martian148/p/13811157.html