前缀和
什么是前缀和?
-
数列的和时,Sn = a1+a2+a3+…an; Sn就是数列的前 n 项和。
-
前缀和就是新建一个数组,新建数组中保存原数组前 n 项的和。
前缀和有什么用? -
快速求某个区间中所有元素的加和。
-
例 S4 = a1 + a2 + a3 + a4; S1 = a1。所以可以通过 S4-S1 得到 a2+a3+a4 的值。
具体做法:
首先做一个预处理,定义一个sum[]
数组,sum[i]
代表a数组中前i个数的和。
求前缀和运算:
const int N = 1e5+10;
int sum[N], a[N]; //sum[i] = a[1] + a[2] + a[3] ..... a[i];
for(int i = 1; i <= n;i++)
{
sum[i] = sum[i - 1] + a[i];
}
然后查询操作:
scanf("%d%d", &l, &r);
printf("%d\n", sum[r] - sum[l - 1]);
对于每次查询,只需执行sum[r] - sum[l - 1] ,时间复杂度为O(1)
原理
sum[r] = a[1] + a[2] + a[3] + a[l-1] + a[l] + a[l+1] ...... a[r];
sum[l - 1] = a[1] + a[2] + a[3] + a[l - 1];
sum[r] - sum[l - 1] = a[l] + a[l + 1]+......+ a[r];
图解
这样,对于每个询问,只需要执行 sum[r]-sum[l-1]
。输出原序列中从第l个数到第r个数的和的时间复杂度变成了O(1)
。
我们把它叫做一维前缀和。
总结:
代码
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e5+10;
int a[N],sum[N];
int main()
{
int n,m,x;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>x;
sum[i]=x+sum[i-1];
}
while(m--)
{
int l,r;
cin>>l>>r;
cout<<sum[r]-sum[l-1]<<endl;
}
return 0;
}
Java代码
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int m = scan.nextInt();
int[] a = new int[n+1];
int[] s = new int[n+1];
for(int i = 1 ; i <= n ; i ++ ){
a[i] = scan.nextInt();
}
for(int i = 1 ; i <= n ; i ++){
s[i] = s[i-1] + a[i];
}
while(m-- > 0){
int l = scan.nextInt();
int r = scan.nextInt();
System.out.println(s[r] - s[l-1]);
}
}
}
二维前缀和
推导
如图:
紫色面积是指(1,1)
左上角到(i,j-1)
右下角的矩形面积, 绿色面积是指(1,1)
左上角到(i-1, j )
右下角的矩形