zl程序教程

您现在的位置是:首页 >  后端

当前栏目

【Python 百练成钢】前缀和

Python 前缀
2023-09-27 14:20:14 时间

前言😇

今天分享一下学到的基础算法前缀和。
首先了解一下前缀和的基础概念😄
有一个序列,序列内包含很多数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)

ฅʕ•̫͡•ʔฅ💯

ᴴᴬᵛᴱ ᴬ ᴳᴼᴼᴰ ᵀᴵᴹᴱ