题目来源:AcWing 795. 前缀和
一、题目描述
输入一个长度为
n
n
n 的整数序列。
接下来再输入
m
m
m 个询问,每个询问输入一对
l
,
r
l,r
l,r。
对于每个询问,输出原序列中从第
l
l
l 个数到第
r
r
r 个数的和。
输入格式
第一行包含两个整数
n
n
n 和
m
m
m。
第二行包含
n
n
n 个整数,表示整数数列。
接下来
m
m
m 行,每行包含两个整数
l
l
l 和
r
r
r,表示一个询问的区间范围。
输出格式
共
m
m
m 行,每行输出一个询问的结果。
数据范围
1
≤
l
≤
r
≤
n
,
1≤l≤r≤n,
1≤l≤r≤n,
1
≤
n
,
m
≤
100000
,
1≤n,m≤100000,
1≤n,m≤100000,
−
1000
≤
−1000≤
−1000≤ 数列中元素的值
≤
1000
≤1000
≤1000
输入样例:
5 3
2 1 3 6 4
1 2
1 3
2 4
输出样例:
3
6
10
二、算法原理
假设有一个序列 a 1 , a 2 , a 3 , . . . , a n a_1,a_2,a_3,...,a_n a1,a2,a3,...,an,现在对这个序列定义一个前缀和序列 s i = a 1 + a 2 + . . . + a i s_i=a_1+a_2+...+a_i si=a1+a2+...+ai。
如何求si
s[0] = 0; // 边界值
for (int i = 1; i <= n; i++) s[i] = s[i - 1] + a[i]; // 注意:前缀和的下标必须从1开始
前缀和的作用
前缀和可以快速的求出序列中某一段序列的和,例如我们需要计算
s
i
=
a
l
+
a
l
+
1
+
.
.
.
+
a
r
s_i=a_l+a_{l+1}+...+a_r
si=al+al+1+...+ar 的和,如果使用传统方法扫描一遍,则时间复杂度是
O
(
n
)
O(n)
O(n) 的。但是如果使用前缀和,我们可以通过下面的公式表达:
a
l
+
a
l
+
1
+
a
l
+
2
+
.
.
.
+
a
r
=
s
r
−
s
l
−
1
n
o
t
e
:
s
r
=
a
1
+
a
2
+
.
.
.
+
a
r
,
s
l
−
1
=
a
1
+
a
2
+
.
.
.
+
a
l
−
1
a_{l}+a_{l+1}+a_{l+2}+...+a_{r} = s_{r} -s_{l-1} \\ note:s_{r} = a_{1}+a_{2}+...+a_{r} ,s_{l-1}=a_{1}+a_{2}+...+a_{l-1}
al+al+1+al+2+...+ar=sr−sl−1note:sr=a1+a2+...+ar,sl−1=a1+a2+...+al−1
时间复杂度仅仅为
O
(
1
)
O(1)
O(1)。
三、代码
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int s[N], n, m;
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
scanf("%d", &s[i]);
s[i] += s[i - 1];
}
while (m--)
{
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", s[r] - s[l - 1]);
}
return 0;
}