Given a sequence of positive numbers, a segment is defined to be a consecutive subsequence. For example, given the sequence { 0.1, 0.2, 0.3, 0.4 }, we have 10 segments: (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) and (0.4).
Now given a sequence, you are supposed to find the sum of all the numbers in all the segments. For the previous example, the sum of all the 10 segments is 0.1 + 0.3 + 0.6 + 1.0 + 0.2 + 0.5 + 0.9 + 0.3 + 0.7 + 0.4 = 5.0.
Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N, the size of the sequence which is no more than 105. The next line contains N positive numbers in the sequence, each no more than 1.0, separated by a space.
Output Specification:
For each test case, print in one line the sum of all the numbers in all the segments, accurate up to 2 decimal places.
Sample Input:
4
0.1 0.2 0.3 0.4
Sample Output:
5.00
Thanks to Ruihan Zheng for correcting the test data.
题意分析:
这道题第一反应就是找规律总结公式
先举个例子{1,2,3,4},n=4,(题目里是<1.0的数,我这里用简单整数代替):
| (1) | 1 | |||
| (2) | 1 | 2 | ||
| (3) | 1 | 2 | 3 | |
| (4) | 1 | 2 | 3 | 4 |
| (5) | 2 | |||
| (6) | 2 | 3 | ||
| (7) | 2 | 3 | 4 | |
| (8) | 3 | |||
| (9) | 3 | 4 | ||
| (10) | 4 |
每个数轮流做当前分割子序列的首数,其中n=4:
- 第一个数出现 1* 4 次
- 第二个数出现 2*(4-1) 次
- 第三个数出现 3*(4-2) 次
- 第四个数出现 4*(4-3) 次
再举几个例子,这里不再赘述。规律已经很明了了,即每个数出现的次数为:
该数所在位置序号i * (n - i + 1)
但是要注意的是,仅仅按以上的规律直接运行的话,测试点2通不过,后来看了柳神的题解才知道是double的问题:
问题分析:N比较大时,double类型的值多次累加导致的精度误差,因为输入为十进制小数,存储到double中时,计算机内部使用二进制表示,且计算机的字长有限,有的十进制浮点数使用二进制无法精确表示只能无限接近,在字长的限制下不可避免会产生舍入误差,这些细微的误差在N较大时多次累加会产生较大误差,所以建议不要使用double类型进行多次累加的精确计算,而是转为能够精确存储的整型。
解决方法:尝试把输入的double类型的值扩大1000倍后转为long long整型累加,同时使用long long类型保存sum的值,输出时除以1000.0转为浮点型再输出(相当于把小数点向后移动3位后再计算,避免double类型的小数部分存储不精确,多次累加后对结果产生影响)
代码如下:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
double tmp;
long long sum=0;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%lf",&tmp);
sum += (long long)(tmp*1000) * (n - i + 1) * i;
}
printf("%.2f\n", sum/1000.0);
return 0;
}
运行结果如下:

该博客讨论了一道编程题目,涉及对一串正数序列进行连续子序列划分,并计算所有子序列的和。题目中指出,当序列大小达到一定数量级时,直接使用double类型进行累加会导致精度误差。解决方案是将输入的浮点数放大1000倍转换为long long整型进行累加,最后输出时再除以1000并保留两位小数。这种方法有效地避免了由于double类型精度不足造成的计算误差。
PAT 甲级Advanced Level Practice(C++)满分题解【子序列数学问题+测试点2注意double带来的误差】&spm=1001.2101.3001.5002&articleId=126019896&d=1&t=3&u=c8f100b37a7b4ba89b52fa4334878de7)
1946

被折叠的 条评论
为什么被折叠?



