【算法】前缀和

【算法】前缀和

题目

先来看一道题目:(前缀和模板题)

已知一个数组A[],现在想要求出其中一些数字的和。
输入格式:
先是整数N,M,表示一共有N个数字,有M组询问
接下来有N个数,表示A[1]..A[N]的数字
接下来是M组询问,每组询问包含两个X,Y,表示想要求出A[X]..A[Y]的和

输出格式:
对于每一组询问,输出A[X]..A[Y]的和。

样例:

输入:
5 3
1 2 3 4 5
1 2
2 5
1 3
输出:
3
14
6

无脑操作

#include<bits/stdc++.h>
using namespace std;
const int Max_N=100000;
int N,M,A[Max_N];
int main(){
  scanf("%d%d",&N,&M);
  for(int i=1;i<=N;i++){
    scanf("%d",A+i);
  }
  for(int i=1;i<=M;i++){
    int X,Y;
    scanf("%d%d",&X,&Y);
    int Ans=0;
    for(int j=X;j<=Y;j++)Ans+=A[j];
    printf("%d\n",Ans);
  }
  return 0;
}

非常无脑的操作,两层循环,时间复杂度:O(N*M)
如果数据范围较大,会造成部分数据点超时,那么如何优化?

前缀和

我们可以使用预处理,在一边输入的时候就能一边计算求和,这样可以加快速度。

我们定义数组S,使得S[i]=A[1]+A[2]+...+A[i],即S[i]就是A数组前i项之和
这样写起来,一边读入就可以一边计算,代码:

for(int i=1;i<=N;i++){
  scanf("%d",A+i);
  S[i]=S[i-1]+A[i];
}

S数组和A数组的对应关系,用样例,手算一下:

A	1	2	3	4	5
S	1	3	6	10	15

正好,S[i]就是A数组前i项之和。那么如果想要求A[X]..A[Y]的和,其实就是求:

A[X]..A[Y]
=A[1]+A[2]+...+A[X]+...+A[Y]-A[1]-A[2]-...-A[X-1]
=S[Y]-S[X-1]

前后抵消,剩余的就是A[X]..A[Y]的一部分。

这就是前缀和的基本思想。

正解

#include<bits/stdc++.h>
using namespace std;
const int Max_N=100000;
int N,M,A[Max_N],S[Max_N];
int main(){
  scanf("%d%d",&N,&M);
  for(int i=1;i<=N;i++){
    scanf("%d",A+i);S[i]=S[i-1]+A[i];
  }
  for(int i=1;i<=M;i++){
    int X,Y;
    scanf("%d%d",&X,&Y);
    printf("%d\n",S[Y]-S[X-1]);
  }
  return 0;
}
posted @ 2022-01-16 11:12  计算机知识杂谈  阅读(83)  评论(0编辑  收藏  举报