【C++算法模板】预处理算法:一维前缀和、二维前缀和总结,详解带例题

0)概述

  • 因为前缀和这个板子的推导比较简单,因此本博客重点在于知识点归纳而不在于证明

1)一维前缀和

  • 一维数组的前缀和计算公式: s [ i ] = ∑ i = 1 i a [ i ] = s [ i − 1 ] + a [ i ] s[i]=\sum_{i=1}^ia[i]=s[i-1]+a[i] s[i]=i=1ia[i]=s[i1]+a[i],时间复杂度 O ( n ) O(n) O(n)
  • 原数组 [ l , r ] [l,r] [l,r] 区间和计算公式: s [ r ] − s [ l − 1 ] s[r]-s[l-1] s[r]s[l1] ,时间复杂度 O ( 1 ) O(1) O(1)

【例题】AcWing 795,链接:795. 前缀和 - AcWing题库

#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;

const int N=1e5+5;
int a[N],s[N];

int main() {
	int n;
	int m;
	cin>>n>>m;
	// 输入规模超过1e5时推荐使用scanf而不是cin和cout
	for(int i=1;i<=n;i++) {
		scanf("%d",&a[i]);
	}
	for(int i=1;i<=n;i++) {
		s[i]=s[i-1]+a[i];	
	}
	while(m--) {
		int l,r;
		scanf("%d%d",&l,&r);
		printf("%d\n",s[r]-s[l-1]);
	}
	return 0;
}	

2)二维前缀和

  • 一维数组的前缀和计算公式: s [ i ] [ j ] = ∑ i = 1 i ∑ j = 1 j a [ i ] [ j ] = s [ i − 1 ] [ j ] + s [ i ] [ j − 1 ] − s [ i − 1 ] [ j − 1 ] + a [ i ] [ j ] s[i][j]=\sum_{i=1}^i\sum_{j=1}^ja[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j] s[i][j]=i=1ij=1ja[i][j]=s[i1][j]+s[i][j1]s[i1][j1]+a[i][j],时间复杂度 O ( n 2 ) O(n^2) O(n2)

在这里插入图片描述

  • 原数组 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) ( x 2 , y 2 ) (x_2,y_2) (x2,y2) 区间和计算公式: s [ x 2 ] [ y 2 ] − s [ x 1 − 1 ] [ y 2 ] − s [ x 2 ] [ y 1 − 1 ] + s [ x 1 − 1 ] [ x 2 − 1 ] s[x_2][y_2]-s[x_1-1][y_2]-s[x_2][y_1-1]+s[x_1-1][x_2-1] s[x2][y2]s[x11][y2]s[x2][y11]+s[x11][x21] ,时间复杂度 O ( 1 ) O(1) O(1)

在这里插入图片描述

【例题】AcWing 796,链接:796. 子矩阵的和 - AcWing题库

#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;

// 容器原理:
const int N=1e3+10;
int n,m,q;
int a[N][N];
int s[N][N]; // 二维前缀和矩阵

int main() {
	cin>>n>>m>>q;
	for(int i=1;i<=n;i++) {
		for(int j=1;j<=m;j++) {
			scanf("%d",&a[i][j]);
			// 预处理二维前缀和数组
			s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
		}
	}
	while(q--) {
		int x1,x2,y1,y2;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		// 算区间和
		printf("%d\n",s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]);
	}
	return 0;
}
  • 23
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值