Problem Description:
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 N N, the size of the sequence which is no more than 1 0 5 10^5 105. The next line contains N N 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
Problem Analysis:
分析样例可知,本题可以先预处理这些数段的前缀和,然后遍历前缀和数组,再找规律求和即可:
for (int i = 1; i <= n; i ++ ) s[i] += s[i - 1] + seq[i];
double res = 0;
for (int i = 0; i < n; i ++ )
for (int j = i + 1; j <= n; j ++ )
res += s[j] - s[i];
但由于 N ≤ 1 0 5 N\leq 10^5 N≤105,这种方法会 TLE,因此考虑优化。
我们可以为 seq
的前缀和数组 s
再维护一个前缀和数组 S
,这样只需要预处理一下 S
,就可以减少一重循环,在线性复杂度下求得答案。
另外,由于数据原因,这里需要开 long double
,其输出格式为 printf("%Lf", res)
。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e5 + 10;
int n;
long double seq[N];
long double s[N], S[N];
int main()
{
cin >> n;
for (int i = 1; i <= n; i ++ ) scanf("%Lf", &seq[i]);
for (int i = 1; i <= n; i ++ ) s[i] = s[i - 1] + seq[i];
for (int i = 1; i <= n; i ++ ) S[i] = S[i - 1] + s[i];
long double res = 0;
for (int i = 0; i < n; i ++ )
{
res += S[n] - S[i] - (n - i) * s[i];
}
printf("%.2Lf\n", res);
return 0;
}