给定一个由 n 个整数组成的序列A1,A2,……, An 和两个整数L,R,你的任务是写一个程序来计算序列号在L,R 这段位置区间内所有数的总和。
输入格式:
输入只有一组测试数据:
测试数据的第一行为一个整数 n (1< n < 10000);
第二行为 n 个 int 类型的整数;
第三行为两个整数 L,R(0 < L < R <= n)。
输出格式:
输出序列号在区间[L,R]内所有数的和,数据保证和在 int 类型范围内。
输入样例:
5
3 5 6 2 9
2 4
输出样例:
13
1.常规做法
根据题目要求遍历数组指定区间即可(注意数据第一个位置是1,要从1开始读入数组)
#include<stdio.h>
int main()
{
int n, l, r, a[10010];
scanf("%d", &n);
for (int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
int sum = 0;
scanf("%d %d", &l, &r);
for (int i = l; i <= r; i ++)
sum += a[i];
printf("%d", sum);
return 0;
}
2.前缀和做法
1.前缀和介绍
前缀和的基本思想是通过预先计算数组中每个位置的前缀和,然后利用这些前缀和快速计算任意区间的和,而不必每次都重新遍历整个区间。
可以将前缀和类比于数学中的数列和
在数列中,已知前n项数列之和,若是求数量第n个数的值可通过以下公式计算:
a n = S n − S n − 1 a_n=S_n-S_{n -1} an=Sn−Sn−1
通过前缀和求某个区间值的思路也是如此,先将前1项,前2项,前3项…前n项的和分别求出,若是想求某个区间的和便可通过大区间减小区间求出。
2.前缀和的优势
仅是求一组数据的区间和,前缀和并没有明显优势,如果数据为多组,可以通过前缀和预先算出每个区间的和,对于每组数据只需做减法运算即可,无需再次遍历。这样做可以用空间换时间,大大减少了程序运行时间。
3.前缀和在本题中的应用
了解了前缀和后,读者需要思考该如何求出一个数组的前缀和。
首先,开辟一个数组来储存数据,既然是要求和,就需要再开辟一个数组来存储数据之和。
以下是前缀和的通用写法:
for (int i = 0; i < n; i ++)
s[i] = s[i - 1] + a[i];
其中s[i]用来储存前 i 的数的总和
本题第一个数的下标为1,所以前缀和应用到本题中可以改写为:
for (int i = 1; i <= n; i ++)
s[i] = s[i - 1] + a[i];
对于样例,想要求2到4区间的和,就需要用s[4] - s[1],通过观察我们不难发现s[4] - s[1]其实就是
s[r] - s[l - 1]
这是前缀和的关键以及易错点,减号右侧数组的下标需要基于题目给的数据减去一,以保证覆盖区间内的每个数。
以下是完整代码:
#include<stdio.h>
int main()
{
int n, a[10010], l, r, s[10010];
scanf("%d", &n);
for (int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
scanf("%d %d", &l, &r);
for (int i = 1; i <= n; i ++)
s[i] = s[i - 1] + a[i];
printf("%d", s[r] - s[l - 1]);
return 0;
}
本题使用的前缀和仅是一维前缀和,想要深入了解二维前缀和以及差分可以阅读以下文章。