CF27E Number With The Given Amount Of Divisors 题解

Update 2022/2/3:感谢 @aresword 大佬的建议,对文章中一个不严谨但是能过题的地方进行修改。


这是一道数学题。

前置知识:

对于一个数 x x x,我们可以将其唯一分解成 p 1 c 1 × p 2 c 2 × . . . × p k c k = ∏ i = 1 k p i c i p_1^{c_1} \times p_2^{c_2} \times ... \times p_k^{c_k}=\prod_{i=1}^{k}p_i^{c_i} p1c1×p2c2×...×pkck=i=1kpici,其中 p i p_i pi 为质数,即分解质因数。都来做这道题了这个肯定是会的吧

引理:

对于唯一分解 x = ∏ i = 1 k p i c i x = \prod_{i=1}^{k}p_i^{c_i} x=i=1kpici x x x 的因数个数为 ∏ i = 1 k ( c i + 1 ) \prod_{i=1}^{k}(c_i+1) i=1k(ci+1)。证明见文末。

那么这道题我们要怎么做呢?

这里要有贪心的思想。

对一个具有 n n n 个因子的数来说,肯定是 2 \text{2} 2 的个数越多越好对不对?当然我们可以举出反例,但是当因子个数不够的时候肯定是增加 2 \text{2} 2 的个数是更优的。

那么这里有一个定理:

对于一个含有 n n n 个正因子的最小数 x = ∏ i = 1 k p i c i x = \prod_{i=1}^{k}p_i^{c_i} x=i=1kpici,如果 ∀ i ∈ [ 1 , k ) , p i < p i + 1 \forall i \in [1,k),p_i < p_{i+1} i[1,k),pi<pi+1,那么可以证明:

  1. p 1 = 2 p_1 = 2 p1=2
  2. p i + 1 p_{i+1} pi+1 p i p_i pi 后面的第一个质数(即连续质数)
  3. ∀ i ∈ [ 1 , k ) , c i + 1 ≤ c i \forall i \in [1,k),c_{i + 1} \leq c_i i[1,k),ci+1ci

证明见文末。

考虑到我们现在不能确定是否一定是 2 \text{2} 2 的个数越多越好,但是相对而言 2 \text{2} 2 的个数越多越好,那么我们采用搜索解决。

首先题目保证答案不超过 1 0 18 10^{18} 1018 ,而 2 64 > 1 0 18 2^{64} > 10^{18} 264>1018,那么我们知道指数最多为 64 \text{64} 64。又因为从 2 \text{2} 2 开始连续 16 \text{16} 16 个质数相乘已经超过 1 0 18 10^{18} 1018,那么我们只需要搜 16 \text{16} 16 个质数,然后加上最优化剪枝以及一些特判即可。

友情提醒:当搜索过程中的答案小于 0 \text{0} 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 = ∏ i = 1 k p i c i x=\prod_{i=1}^{k}p_i^{c_i} x=i=1kpici 中,我们将 p i p_i pi 看作 k k k 个箱子,在每一个箱子中我们可以取出 c i + 1 c_i+1 ci+1 个数,分别为 p i 0 , p i 1 , . . . , p i k p_i^0,p_i^1,...,p_i^k pi0,pi1,...,pik

考虑到所有 p i p_i pi 都是质数,因此不会有取出的数字重复。

由乘法原理,正因子个数为 ∏ i = 1 k ( c i + 1 ) \prod_{i=1}^{k}(c_i+1) i=1k(ci+1)

定理的证明:

  1. p i = 2 p_i=2 pi=2

这个其实很好想,毕竟如果我们把 p 1 p_1 p1 换成比 2 \text{2} 2 更大的数字显然答案只会更劣。

  1. p i + 1 p_{i+1} pi+1 p i p_i pi 后的第一个质数。

这个也很好证明。

对于一个确定的 ( c i , c i + 1 ) (c_i,c_{i+1}) (ci,ci+1),由于规定 ∀ i ∈ [ 1 , k ) , p i < p i + 1 \forall i \in [1,k),p_i < p_{i+1} i[1,k),pi<pi+1,那么如果 “ p i + 1 p_{i+1} pi+1 p i p_i pi 后的第一个质数” 不成立,那么 p i + 1 p_{i+1} pi+1 只能变得更大,答案显然更劣。

  1. ∀ i ∈ [ 1 , k ) , c i + 1 ≤ c i \forall i \in [1,k),c_{i + 1} \leq c_i i[1,k),ci+1ci

由于 p i < p i + 1 p_i < p_{i+1} pi<pi+1,那么我们假设 c i < c i + 1 c_i < c_{i+1} ci<ci+1,这一段的答案为 p i c i × p i + 1 c i + 1 p_i^{c_i} \times p_{i+1}^{c_{i+1}} pici×pi+1ci+1

如果我们交换指数,因子个数不变,答案为 p i c i + 1 × p i + 1 c i p_i^{c_{i+1}} \times p_{i+1}^{c_i} pici+1×pi+1ci

此时根据前文所述,显然越大的指数要配越小的质数,那么 c i < c i + 1 c_i < c_{i+1} ci<ci+1 的答案比 c i + 1 ≤ c i c_{i+1} \leq c_i ci+1ci 更劣。

证毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值