序列求和【蓝桥杯国赛】

序列求和

试题 E: 序列求和
本题总分:15 分
【问题描述】
学习了约数后,小明对于约数很好奇,他发现,给定一个正整数 t,总是可
以找到含有 t 个约数的整数。小明对于含有 t 个约数的最小数非常感兴趣,并
把它定义为 S t 。
例如 S 1 = 1, S 2 = 2, S 3 = 4, S 4 = 6,···。
现在小明想知道,前 60 个 S i 的和是多少?即 S 1 + S 2 + ··· + S 60 是多少?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

算法

本题需要知道:唯一分解定理,并且要知道一个数约数的个数与它的质因数分解结果的关系。

到这里,假设你已经知道了上述前置知识。

我们要求最小的一个数X,使得它的约数个数为cnt,我们直接求解发现没有什么好的方法,瞄一眼题意中的数据范围,发现只有60,所以我们可以往暴力方向去想,我们定义一个数组ans,ans[i]表示约数个数为i的最小值,具体的求法我们可以枚举。该数的质因数的次幂,由于数据范围只有60,我们可以把最大的质因数限制为7,枚举2,3,5,7的次幂,假设他们的次幂分别是:i,j,k,u,由于约数个数为 ( i + 1 ) ( j + 1 ) ( k + 1 ) ( u + 1 ) (i + 1)(j + 1)(k + 1)(u + 1) (i+1)(j+1)(k+1)(u+1),那么他们的值 t t t 2 i − 1 × 2 j − 1 × 2 k − 1 × 2 u − 1 2^{i- 1}\times2^{j - 1}\times2^{k-1}\times2^{u - 1} 2i1×2j1×2k1×2u1,我们更新ans[i * j * k * u] = min(ans[i * j * k * u], t)

最后我们定义答案 r e s = 0 res = 0 res=0,枚举 i : 1 ∼ 60 i :1 \sim 60 i:160,将答案加上ans[i]即可。

AC代码(C++)

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef unsigned long long LL;

const int N = 65;

LL ans[N];

LL qmi(LL a, LL b) {
	LL res = 1;
	while(b) {
		if(b & 1) res = res * a;
		b >>= 1;
		a = a * a;
	}
	return res;
}

int main() {
	for(int i = 1; i <= 60; i ++) ans[i] = 1e18;
	
	for(int i = 1; i <= 60; i ++)
		for(int j = 1; j <= i; j ++)
			for(int k = 1; k <= j; k ++)
				for(int u = 1; u <= k; u ++)
				{
					if(i * j * k * u > 60) break;
					LL t = qmi(2, i - 1) * 
						qmi(3, j - 1) * qmi(5, k - 1) * qmi(7, u - 1);
					ans[i * j * k * u] = min(ans[i * j * k * u], t);
				}
	
	LL res = 0;
	for(int i = 1; i <= 60; i ++) res += ans[i];
	
	cout << res << "\n";
	return 0;
}
posted @ 2023-04-06 23:34  openallzzz  阅读(12)  评论(0编辑  收藏  举报  来源