前言😇
今天分享一下学到的基础算法前缀和。
首先了解一下前缀和的基础概念😄
有一个序列,序列内包含很多数a1、a2、a3、a4、a5、a6、a7
a1的前缀和就是a1
a2的前缀和就是a1+a2
a3的前缀和就是a1+a2+a3
…
此时可以定义一个序列bn专门用于存放关于an的前缀和
b1、b2、b3、b4、b5、b6、b7…
使得:
b1=a1
b2=a1+a2
b3=a1+a2+a3
…
这样就得到了一个关于a序列的前缀和序列,在进行一些运算的时候可以大大的降低时间复杂度。
写题的时候步骤就是
(1)确定前缀和序列
(2)使用位置关系对前缀和序列进行查询,得到想要的结果
具体如何用听我细细道来
一维前缀和😈
问题描述
输入一个长度为n的整数序列。
接下来再输入m个询问,每个询问输入一对l, r。
对于每个询问,输出原序列中从第l个数到第r个数的和。
输入格式
第一行包含两个整数n和m。
第二行包含n个整数,表示整数数列。
接下来m行,每行包含两个整数l和r,表示一个询问的区间范围。
输出格式
共m行,每行输出一个询问的结果。
数据范围
1≤l≤r≤n,
1≤n,m≤100000,
−1000≤数列中元素的值≤1000
输入样例:
5 3
2 1 3 6 4
1 2
1 3
2 4
输出样例:
3
6
10
问题分析
对于一维前缀和直接构造前缀和序列即可,然后打印l与r位置的前缀和元素之差。
可以将所有的结果先添加到一个序列中,在输入所有操作之后一块打印。
代码实现
老规矩先上运行结果:
# 暴力解决 ''' import sys n,m=sys.stdin.readline().strip().split() n,m=int(n),int(m) nls=[] ans=[] ls=[int(x) for x in sys.stdin.readline().strip().split()] for i in range(m): l,r=sys.stdin.readline().strip().split() l,r=int(l),int(r) sum=0 for i in range(l-1,r): sum+=ls[i] ans.append(sum) print(ans) ''' # 前缀和 ''' 先将数据处理一下,然后在进行计算的时候就是进行查询 显然进行查询要方便的多。 ''' import sys n,m=sys.stdin.readline().strip().split() n,m=int(n),int(m) ls=[int(x) for x in sys.stdin.readline().strip().split()] als=[] ans=[] als.append(0) ans.append(0) # print(ls,als,ans) als.append(ls[0]) for j in range(1,n): als.append(als[len(als)-1]+ls[j]) for i in range(m): l,r=sys.stdin.readline().strip().split() r,l=int(r),int(l) ans.append(als[r]-als[l-1]) # print(ans) for i in range(1,m+1): print(ans[i])
二维前缀和👿
问题描述
输入一个n行m列的整数矩阵,再输入q个询问,每个询问包含四个整数x1, y1, x2, y2,表示一个子矩阵的左上角坐标和右下角坐标。
对于每个询问输出子矩阵中所有数的和。
输入格式
第一行包含三个整数n,m,q。
接下来n行,每行包含m个整数,表示整数矩阵。
接下来q行,每行包含四个整数x1, y1, x2, y2,表示一组询问。
输出格式
共q行,每行输出一个询问的结果。
数据范围
1≤n,m≤1000,
1≤q≤200000,
1≤x1≤x2≤n,
1≤y1≤y2≤m,
−1000≤矩阵内元素的值≤1000
输入样例:
3 4 3
1 7 2 4
3 6 2 8
2 1 2 3
1 1 2 2
2 1 3 4
1 3 3 4
输出样例:
17
27
21
问题分析
应准备一个矩阵,一个用于存放以(1,1)与(x1,y1)矩阵中的元素和
在进行求取面积内元素和的时候,使用矩阵元素之间的关系。
此时面临两个问题(可以配合图片进行理解):
对于以下图片中均是左边代表原始矩阵,右边代表和矩阵
一、矩阵求求和
对应颜色矩阵的框所有数的和求出来后放进对应颜色的位置
由于矩阵叠加,所以我们在进行求和的时候应先加然后再减去叠加的部分故可得:
b33=a33+b32+b23-b22
二、矩阵求差
(这也是最终面临的问题)
由于矩阵叠加,所以我们在进行求差的时候应先减去矩阵周围的矩阵和,然后加上重复减去的部分:
故可得下标为a22与a33围成的矩阵所有元素和为:b22-33=b33-b31+b13+b11
这里进行求解的时候可能面临坐标交换,a22-a33围成的矩阵,与a32-a23围成的是一个矩阵
所以我们不妨将ax1y1中的下标均换成最小的便于计算。(也就是说转换成x1<x2,y1<y2)
然后以最小的坐标与最大的坐标为界,减去所求矩阵周围的矩阵
代码实现
老规矩先上运行结果:
import sys ans=[] # 原始矩阵 amatrix=[] # 前缀和矩阵 bmatrix=[] # 读入n,m,q并将其转换为数值类型 n,m,q=sys.stdin.readline().strip().split() n,m,q=int(n),int(m),int(q) # 初始化前缀和矩阵 for i in range(n+1): bmatrix.append([0]*(m+1)) # 读入原始矩阵 for i in range(n): amatrix.append([int(x) for x in sys.stdin.readline().strip().split()]) #利用原始矩阵,求前缀和矩阵 i=1 # 行 while i<=n: j=1 # 列 while j<=m: bmatrix[i][j]=amatrix[i-1][j-1]+bmatrix[i][j-1]+bmatrix[i-1][j]-bmatrix[i-1][j-1] j+=1 i+=1 # 测试是否创建前缀和矩阵成功 # for i in bmatrix: # print(i) # 写入坐标矩阵 qm=[] for i in range(q): qm.append([int(x) for x in sys.stdin.readline().strip().split()]) # 计算某段矩阵的和 i=0 while i<q: # 处理矩阵中的xy,确保x2y2在矩阵的右下方便于后面计算 if qm[i][0]>qm[i][2]: qm[i][0],qm[i][2]=qm[i][2],qm[i][0] if qm[i][1]>qm[i][3]: qm[i][1],qm[i][3]=qm[i][3],qm[i][1] ans.append(bmatrix[qm[i][2]][qm[i][3]]-bmatrix[qm[i][0]-1][qm[i][3]]-bmatrix[qm[i][2]][qm[i][1]-1]+bmatrix[qm[i][0]-1][qm[i][1]-1]) # print(qm[i]) i+=1 # 结果输出 print(ans)