1049 数列的片段和 (20 分)
给定一个正数数列,我们可以从中截取任意的连续的几个数,称为片段。例如,给定数列 { 0.1, 0.2, 0.3, 0.4 },我们有 (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) 这 10 个片段。
给定正整数数列,求出全部片段包含的所有的数之和。如本例中 10 个片段总和是 0.1 + 0.3 + 0.6 + 1.0 + 0.2 + 0.5 + 0.9 + 0.3 + 0.7 + 0.4 = 5.0。
输入格式:
输入第一行给出一个不超过 105的正整数 N,表示数列中数的个数,第二行给出 N 个不超过 1.0 的正数,是数列中的数,其间以空格分隔。
输出格式:
在一行中输出该序列所有片段包含的数之和,精确到小数点后 2 位。
输入样例:
4
0.1 0.2 0.3 0.4
输出样例:
5.00
感谢 Ruihan Zheng 对测试数据的修正。
思路对于105的数据来说,嵌套双循环一定不会满足条件,所以必须从循环顺序、借用循环执行、利用数据的关系等等不一样的方法来“化简”运算的次数,从而减少时间复杂度。
1.循环顺序化简运算次数的大致意思就是:从前往后或者从后往前循环从而节省次数。如例题中找出最大的 m-n 的最大值。PAT乙级1050
2.借用循环执行意思就是:记住记录以前的情况,为不需要再进行多的循环。如例题中用 max 来储存主元的左边的所有数的最大值,主元一移动就与 max 作比较,节省循环次数。
例题:https://blog.csdn.net/qq_53269459/article/details/113855435
3.利用数据关系意思就是:找出数据之间的关系,列出循环,此题即使这种方法。
而这题的简化算法
1 //第一个数要加够 n 次,然后个数加的个数递减
1 2 //但再第二次循环的时候从第二数开始,所以又要加 n-1 次,直到最后一个数
1 2 3
1 2 3 4
1 2 3 4 52
2 3
2 3 4
2 3 4 53
3 4
3 4 54
4 55
所以简化后就是用
int i = 0;
sum += a[i]*(n-i)*(i+1); //用来表示相加的每个数,sum 用来求所有的和。
但这道题出现了问题,就是 double 型数据,二进制数据无法精确转换为 double 型,在多个数相加后会出现很大的误差,这就是原因所在,所以改成乘1000 再除掉的方法,但这种方法仍有漏洞。因为,10^5^的数据误差在0.00001还小,并不能仅仅通过乘 1000 的方法解决。并且对于 long long 型的数据在 乘10000后会出现超过 21 位的情况。所以有人对本提出了的想法,并更改了本题。 我认为,对于这题来说,对条件:小于正整数 1.0 再加一个下限范围就可避免这种错误。详细可参见更改人的博客:[https://blog.zhengrh.com/post/about-double/](https://blog.zhengrh.com/post/about-double/)
#include<stdio.h>
int main()
{
double a; //【测试点3】数据长度问题int n;long long sum = 0;scanf("%d",&n);for(int i = 0;i < n;i++){
scanf("%lf",&a);sum = sum+(long long)(a*1000*(n-i)*(i+1) ); } printf("%.2lf",(double)sum/1000.0);return 0;
}