1. 程式人生 > 遊戲資訊 >第四章——副露判斷(答案部分·五)

第四章——副露判斷(答案部分·五)

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}\),那麼可以證明:

  1. \(p_1 = 2\)
  2. \(p_{i+1}\)\(p_i\) 後面的第一個質數(即連續質數)
  3. \(\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)\)

定理的證明:

  1. \(p_i=2\)

這個其實很好想,畢竟如果我們把 \(p_1\) 換成比 \(\text{2}\) 更大的數字顯然答案只會更劣。

  1. \(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}\) 只能變得更大,答案顯然更劣。

  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\) 更劣。

證畢。