序列求和【蓝桥杯国赛】
序列求和
试题 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}
2i−1×2j−1×2k−1×2u−1,我们更新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:1∼60,将答案加上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;
}