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; }
BZOJ 1053 - 反素數ant - [數論+DFS][HAOI2007]