// 暴力超时
#include <bits/stdc++.h>
using namespace std;
int main() {
// 截取连续片段 计算片段和
// 一种方法 顺序循环从第一位开始
// 用一个片段和变量记录之前所走过变量的和 并累加到结果
double n, part, sum = 0, a[100000];
cin >> n;
for(int i = 0; i < n; i++){
cin >> a[i];
}
// 一重循环 遍历所有数
for(int i = 0; i < n; i++){
// 将独立的元素加入 并重置片段和
sum += a[i], part = a[i];
// 二重循环遍历当前数的后面的数
for(int j = i + 1; j < n; j++){
part += a[j], sum += part;
}
}
// 保留两位小数
cout << fixed << setprecision(2) << sum;
}
#include <bits/stdc++.h>
using namespace std;
int main() {
long double n, part = 0, sum = 0, tmp;
cin >> n;
// (0.1) (0.1, 0.2) (0.1, 0.2, 0.3) (0.1, 0.2, 0.3, 0.4)
// (0.2) (0.2, 0.3) (0.2, 0.3, 0.4)
// (0.3) (0.3, 0.4)
// (0.4)
for(int i = 0; i < n; i++){
cin >> tmp;
// 片段和
part += tmp * (i + 1), sum += part;
}
// 保留两位小数
cout << fixed << setprecision(2) << sum;
}
暴力果然会超时,然后想了某些方法,比如要怎么保存前面的部分和,或者能不能找到部分和的递推公式。
最后从题目给出的序列入手,观察规律,拆分为第一、第二到第n个数时候的情况,平行展开后可以发现。同一个数在不同的列里面出现的次数,与该数的位置存在关系。
这样就可以对原来部分和的概念做一个化简,将二重循环的暴力解法缩小成线性循环,每次统计新的部分和并累加到结果即可。
不过用之前的基本数据类型会过不了测试点二,看别人的参考用到了 long double 数据类型,避免溢出。
所以这可以总结一下,当我们感觉有些思路没错的时候,也许是数据类型溢出导致结果错误,常见的就是 int 转换成 long long,这里还学到如果是 double 也可能溢出,可以转换为 long double。
看别人还有一种方法是把全部数出现的次数列出来,然后与位置找关系,算出每一个数的和然后累加。这是不同的分类的思路,对象聚焦于每一个元素上面,我这里侧重的还是看出部分和。