1. 程式人生 > >BZOJ 1053 - 反素數ant - [數論+DFS][HAOI2007]

BZOJ 1053 - 反素數ant - [數論+DFS][HAOI2007]

因子 its cep ble geo cin first 滿足 討論

題目鏈接: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;
}

BZOJ 1053 - 反素數ant - [數論+DFS][HAOI2007]