第四章——副露判斷(答案部分·五)
Update 2022/2/3:感謝 @aresword 大佬的建議,對文章中一個不嚴謹但是能過題的地方進行修改。
這是一道數學題。
前置知識:
對於一個數 \(x\),我們可以將其唯一分解成 \(p_1^{c_1} \times p_2^{c_2} \times ... \times p_k^{c_k}=\prod_{i=1}^{k}p_i^{c_i}\),其中 \(p_i\) 為質數,即分解質因數。都來做這道題了這個肯定是會的吧
引理:
對於唯一分解 \(x = \prod_{i=1}^{k}p_i^{c_i}\),\(x\) 的因數個數為 \(\prod_{i=1}^{k}(c_i+1)\)
那麼這道題我們要怎麼做呢?
這裡要有貪心的思想。
對一個具有 \(n\) 個因子的數來說,肯定是 \(\text{2}\) 的個數越多越好對不對?當然我們可以舉出反例,但是當因子個數不夠的時候肯定是增加 \(\text{2}\) 的個數是更優的。
那麼這裡有一個定理:
對於一個含有 \(n\) 個正因子的最小數 \(x = \prod_{i=1}^{k}p_i^{c_i}\),如果 \(\forall i \in [1,k),p_i < p_{i+1}\),那麼可以證明:
- \(p_1 = 2\)
- \(p_{i+1}\) 是 \(p_i\) 後面的第一個質數(即連續質數)
- \(\forall i \in [1,k),c_{i + 1} \leq c_i\)
證明見文末。
考慮到我們現在不能確定是否一定是 \(\text{2}\) 的個數越多越好,但是相對而言 \(\text{2}\) 的個數越多越好,那麼我們採用搜尋解決。
首先題目保證答案不超過 \(10^{18}\) ,而 \(2^{64} > 10^{18}\),那麼我們知道指數最多為 \(\text{64}\)。又因為從 \(\text{2}\) 開始連續 \(\text{16}\) 個質數相乘已經超過 \(10^{18}\),那麼我們只需要搜 \(\text{16}\) 個質數,然後加上最優化剪枝以及一些特判即可。
友情提醒:當搜尋過程中的答案小於 \(\text{0}\) 的時候說明此時答案爆 long long
了,此時需要停止搜尋。
這裡新增一個說明:其實答案爆 long long
並不一定是答案小於 0,也可以大於 0,但是按照我的程式的邏輯答案爆 long long
和答案小於 0 互為充要條件,因此這麼寫是沒問題的。
更正確的寫法參考判斷C語言的算術運算越界問題 - dennis_fan - 部落格園。
程式碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 30;
int n, prime[MAXN] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};
LL ans = 0x7f7f7f7f7f7f7f7f;
int read()
{
int sum = 0, fh = 1; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') fh = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {sum = (sum << 3) + (sum << 1) + (ch ^ 48); ch = getchar();}
return sum * fh;
}
void dfs(LL now, int k, int last, int cnt)
{
if (cnt > n) return ;
if (now <= 0ll) return ;
if (now > ans) return ;
if (k > 16) return ;
if (cnt == n) {ans = now; return ;}
for (int i = 1; i <= last; ++i)
dfs(now *= prime[k], k + 1, i, cnt * (i + 1));
}
int main()
{
n = read();
dfs(1ll, 1, 64, 1);
printf("%lld\n", ans);
return 0;
}
證明:
引理的證明:
考慮在 \(x=\prod_{i=1}^{k}p_i^{c_i}\) 中,我們將 \(p_i\) 看作 \(k\) 個箱子,在每一個箱子中我們可以取出 \(c_i+1\) 個數,分別為 \(p_i^0,p_i^1,...,p_i^k\)。
考慮到所有 \(p_i\) 都是質數,因此不會有取出的數字重複。
由乘法原理,正因子個數為 \(\prod_{i=1}^{k}(c_i+1)\)。
定理的證明:
- \(p_i=2\)。
這個其實很好想,畢竟如果我們把 \(p_1\) 換成比 \(\text{2}\) 更大的數字顯然答案只會更劣。
- \(p_{i+1}\) 是 \(p_i\) 後的第一個質數。
這個也很好證明。
對於一個確定的 \((c_i,c_{i+1})\),由於規定 \(\forall i \in [1,k),p_i < p_{i+1}\),那麼如果 “\(p_{i+1}\) 是 \(p_i\) 後的第一個質數” 不成立,那麼 \(p_{i+1}\) 只能變得更大,答案顯然更劣。
- \(\forall i \in [1,k),c_{i + 1} \leq c_i\)
由於 \(p_i < p_{i+1}\),那麼我們假設 \(c_i < c_{i+1}\),這一段的答案為 \(p_i^{c_i} \times p_{i+1}^{c_{i+1}}\)。
如果我們交換指數,因子個數不變,答案為 \(p_i^{c_{i+1}} \times p_{i+1}^{c_i}\)。
此時根據前文所述,顯然越大的指數要配越小的質數,那麼 \(c_i < c_{i+1}\) 的答案比 \(c_{i+1} \leq c_i\) 更劣。
證畢。