BZOJ 1053 - 反素数ant - [数论+DFS][HAOI2007]

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1053

 

题解:

可以证明,$1 \sim N$ 中最大的反质数,就是 $1 \sim N$ 中约数个数最多的数中,最小的那个。

证明:假设 $1 \sim N$ 中最大的反质数 $x$ 不是 $1 \sim N$ 中约数个数最多的,那么必然存在至少一个不等于 $x$ 的数字 $y$,它是 $1 \sim N$ 中约数个数最多的数中最小的,显然有 $g(y) > g(x)$。

那么,分类讨论两种情况:

  1、$x < y$,显然 $[1,y)$ 中不可能找到一个 $i$ 使得 $g(y) \le g(i)$,因此 $g(y)$ 是一个反质数,且 $x < y$,$y$ 优于 $x$,不可能选 $x$ 作为答案。

  2、$y > x$,此时 $g(y) > g(x)$,$x$ 不是一个反质数,不应当选择 $x$ 作为答案。

因此,不管怎么样,都不可能选择 $x$ 作为答案,因此只能选择 $1 \sim N$ 中约数个数最多的数作为答案,又显然的,应当选这些数字中最小的那一个。

证毕。

然后,我们可以进一步考虑,在给出的 $N \le 2e9$ 的前提下,$1 \sim N$ 中的任何数,其不相同质因子的个数不会超过 $10$ 个,因为 $2 \times 3 \times 5 \times 7 \times 11 \times 13 \times 17 \times 19 \times 23 \times 29 = 6469693230 > 2e9$。

同时,$1 \sim N$ 中的任何数,其任意一个质因子的幂次都不会超过 $30$,因为 $2^{31} > 2e9$。

最后,还可以证明 $x$ 如果是一个反质数,那么必然可以分解质因数成 $2^{c_1} \times 3^{c_2} \times 5^{c_3} \times 7^{c_4} \times 11^{c_5} \times 13^{c_6} \times 17^{c_7} \times 19^{c_8} \times 23^{c_9} \times 29^{c_{10}}$,且满足 $c_1 \ge c_2 \ge \cdots \ge c_{10} \ge 0$。

这个是因为,假设 $x$ 有一个质因子 $p>29$,那么 $2 \sim 29$ 这 $10$ 个质数必然至少有一个不能整除 $x$ 了,假设这个质数是 $q$,那么显然如果将 $p^k$ 换成 $q^k$,$x$ 就会变小,而且约数个数不变,也即存在一个 $x'<x$ 且 $g(x') = g(x)$,那么 $x$ 就不是反质数,证毕。

 

综上,我们可以暴力搜索  $2^{c_1} \times 3^{c_2} \times 5^{c_3} \times 7^{c_4} \times 11^{c_5} \times 13^{c_6} \times 17^{c_7} \times 19^{c_8} \times 23^{c_9} \times 29^{c_{10}}$ 中的 $c_1 \sim c_{10}$。我们可以通过 $c_1 \sim c_{10}$ 算出对应的约数个数,我们只需要维护约数个数最多的最小数即可。

 

AC代码(1A很舒服):

/**************************************************************
    Problem: 1053
    User: Dilthey
    Language: C++
    Result: Accepted
    Time:24 ms
    Memory:1288 kb
****************************************************************/
 
#include<bits/stdc++.h>
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
using namespace std;
typedef long long ll;
 
ll n;
int p[10]={2,3,5,7,11,13,17,19,23,29}, c[10];
 
pair<ll,int> ans;
void dfs(int pos,int limit,ll num,int cnt)
{
    if(pos>=10)
    {
        if(cnt>ans.se) ans=mk(num,cnt);
        if(cnt==ans.se && num<ans.fi) ans=mk(num,cnt);
        return;
    }
 
    for(ll i=0,now=1;i<=limit;i++,now*=p[pos])
    {
        if(num*now>n) break;
        dfs(pos+1,i,num*now,cnt*(i+1));
    }
}
 
int main()
{
    cin>>n;
    ans=mk((ll)(2e9+50),0);
    dfs(0,30,1LL,1);
    cout<<ans.fi<<endl;
}

 

posted @ 2019-04-08 23:28  Dilthey  阅读(233)  评论(0编辑  收藏  举报