CF27E Number With The Given Amount Of Divisors 题解

20 篇文章 1 订阅
9 篇文章 0 订阅
这是一篇关于解决 CF27E Number With The Given Amount Of Divisors 题目的博客。博主通过质因数分解的方法,分析了如何找到最小的数 s,这个数恰好有 n 个因数,且 n 的上限为 10^3,同时保证 s 不超过 10^18。文章提到了最大质因数为 53,通过从大到小枚举质因数的指数并计算因数数量来搜索答案。最终代码实现了 O(wys) 的时间复杂度,成功获得了 100 分。
摘要由CSDN通过智能技术生成

博客园同步

原题链接

简要题意:

求最小的有 n n n 个因数的数 s s s n ≤ 1 0 3 n \leq 10^3 n103 ,保证 s ≤ 1 0 18 s \leq 10^{18} s1018.

考虑质因数分解:

s = ∏ i = 1 k p i a i s = \prod_{i=1}^k p_i^{a_i} s=i=1kpiai

p i p_i pi 为质数。那么 s s s 的因数个数就会是

∏ i = 1 k ( a i + 1 ) \prod_{i=1}^k (a_i + 1) i=1k(ai+1)

考虑最大的 p i p_i pi 会是几呢?

2 ∗ 3 ∗ 5 ∗ 7 ∗ 11 ∗ 13 ∗ 17 ∗ 19 ∗ 23 ∗ 29 ∗ 31 ∗ 37 ∗ 41 ∗ 43 ∗ 47 = 614889782588491410 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29 * 31 * 37 * 41 * 43 * 47 = 614889782588491410 23571113171923293137414347=614889782588491410,约为 6.1 × 1 0 17 6.1 \times 10^{17} 6.1×1017,所以 p i p_i pi 最大为 53 53 53.

考虑搜索从大到小枚举当前 p i p_i pi 的指数,并计算当前的因数个数与 s s s.

具体代码具体分析:

inline void dfs(ll dep,ll temp,ll num,ll last) {
	//dep 是当前搜索的素数编号 , temp 是当前的数 , num 是 temp 的因数个数 , last 表示当前最大的指数
	if(num>n || dep>16) return; //超出范围
	if(num==n && ans>temp) {
		ans=temp; return; //更新答案
	} for(int i=1;i<=last;i++) {
		if(temp/p[dep]>ans) break; //最优性剪枝
		dfs(dep+1,temp=temp*p[dep],num*(i+1),i); //往下走一层
	}
}

p p p 是提前打好的素数表,只需要打 16 16 16 个。

dfs(0,1,1,64);

最后输出 ans \text{ans} ans 即可得到答案。

时间复杂度: O ( wys ) \mathcal{O}(\text{wys}) O(wys).

实际得分: 100 p t s 100pts 100pts.

细节:

你可能需要 unsigned long long \text{unsigned long long} unsigned long long,因为答案溢出最大可以到 temp * p[dep] long long \text{long long} long long 应该不能过。

#include<bits/stdc++.h>
using namespace std;
 
inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
	int x=0;while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x*f;}
 
typedef unsigned long long ll;
#define INF ~0LL
ll p[16]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
 
ll n,ans;
inline void dfs(ll dep,ll temp,ll num,ll last) {
	if(num>n || dep>16) return;
	if(num==n && ans>temp) {
		ans=temp; return;
	} for(int i=1;i<=last;i++) {
		if(temp/p[dep]>ans) break;
		dfs(dep+1,temp=temp*p[dep],num*(i+1),i);
	}
}
 
int main(){
	ans=INF;
	n=read();
	dfs(0,1,1,64);
	printf("%llu\n",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值