1049 数列的片段和 (20 point(s))

// 暴力超时
#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。

测试点二


看别人还有一种方法是把全部数出现的次数列出来,然后与位置找关系,算出每一个数的和然后累加。这是不同的分类的思路,对象聚焦于每一个元素上面,我这里侧重的还是看出部分和。

参考代码

posted on 2021-09-01 17:52  Atl212  阅读(55)  评论(0编辑  收藏  举报

导航