今天分享一下学到的基础算法前缀和。
首先了解一下前缀和的基础概念
有一个序列,序列内包含很多数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然后以最小的坐标与最大的坐标为界,减去所求矩阵周围的矩阵
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)
ᴴᴬᵛᴱ ᴬ ᴳᴼᴼᴰ ᵀᴵᴹᴱ