Acwing 学习笔记 // 前缀和 and 差分

一维前缀和

对数组a[i]中前i个元素求和,记prefix_sum[i+1] = prefix_sum[i] + a[i] // prefix_sum[i]即为a[i]前缀和

计算一维前缀和
    1. prefix_sum[i+1] = prefix_sum[i] + a[i] // 前缀和数组下标从1开始
def p_sum(a,n):
	"""
	a为原数组,n为原数组的长度
	"""
	prefix_sum = [0] * (n+1) # 数组长度为n+1,数组的下标从1开始
	# 将prefix_sum[0]定义为0的作用:减少对prefix_sum[0]的特判,
	# 求区间[1,r]也可直接用公式计算:prefix_sum[r] - prefix_sum[0]
	for i in range(n):
		prefix_sum[i+1] = prefix_sum[i] + a[i]
前缀和的作用

用O(1)时间复杂度快速求出原数组中的一段区间和[l,r]:sum[l,r] = prefix_sum[r] - prefix_sum[l-1]

Acwing 795

def main():
    s = input().split()
    n = int(s[0])
    m = int(s[1])
    s2 = input().split()
    prefix_sum = [0] * (n+1)
    for i in range(n):
        prefix_sum[i+1] = prefix_sum[i] + int(s2[i])
    while m:
        s3 = input().split()
        l = int(s3[0])
        r = int(s3[1])
        print(prefix_sum[r] - prefix_sum[l-1])
        m -= 1
main()

二维前缀和

计算二维前缀和

prefix_sum[i+1][j+1] = prefix_sum[i][j+1] + prefix_sum[i+1][j] - prefix_sum[i][j]

def p_sum(arr,n.m):
	"""
	arr表示原数组,n表示行数,m表示列数
	"""
	prefix_sum = [[0] * (m+1) for _ in range(n+1)] # 生成一个前缀和矩阵,用于存放前缀和
	for i in range(n):
		for j in range(m):
			prefix_sum[i+1][j+1] = prefix_sum[i][j+1] + prefix_sum[i+1][j] - prefix_sum[i][j]
二维前缀和计算区间[x1,y1,x2,y2]的和

sum[x1,y1,x2,y2]] = prefix_sum[x2][y2] - prefix_sum[x2][y1-1] - prefix_sum[x1-1][y2] + prefix_sum[x1-1][y2-1]

Acwing 796

def main():
    s1 = input().split()
    n,m,q = int(s1[0]),int(s1[1]),int(s1[2])
    prefix_sums = [[0] * (m+1) for j in range(n+1)]
    for i in range(n):
        line = input().split()
        for j in range(m):
            # 计算二维矩阵的前缀和
            prefix_sums[i+1][j+1] = prefix_sums[i+1][j] + prefix_sums[i][j+1] - prefix_sums[i][j] + int(line[j])
    while q:
        s = input().split()
        x1,y1,x2,y2 = int(s[0]),int(s[1]),int(s[2]),int(s[3])
        res = prefix_sums[x2][y2] - prefix_sums[x2][y1-1] - prefix_sums[x1-1][y2] + prefix_sums[x1-1][y1-1]
        q -= 1
        print(res)
main()

差分

差分为前缀和的逆运算,b[i] = a[i] - a[i-1]

差分的作用

用O(1)的时间复杂度快速对区间[l,r]的所有元素加上一个值c

  • 方法
def insert_c(lists,l,r,c):
    """
    在差分数组中区间l-r之间插入一个数c
    对差分数组求前缀和的时候,r右边的所有数由于进行了+c -c,所以插入的数不会对r右边的前缀和产生影响
    :param lists: 差分数组
    :param l: 区间左端点
    :param r: 区间右端点
    :param c: 要插入的数
    :return:
    """
    lists[l] += c
    lists[r+1] -= c

Acwing 797

def insert_c(lists,l,r,c):
    """
    在差分数组中区间l-r之间插入一个数c
    对差分数组求前缀和的时候,r右边的所有数由于进行了+c -c,所以插入的数不会对r右边的前缀和产生影响
    :param lists: 差分数组
    :param l: 区间左端点
    :param r: 区间右端点
    :param c: 要插入的数
    :return:
    """
    
    lists[l] += c
    lists[r+1] -= c
    
def main():
    s = input().split()
    lists = input().split()
    lists.insert(0,'0')
    n,m = int(s[0]),int(s[1])
    b = [0] * (n+10)
    for i in range(1,n+1):
        # insert的同时对r+1进行了-a[i]操作,等价于:b[i] = a[i] - a[i-1]
        insert_c(b,i,i,int(lists[i]))

    while m:
        s1 = input().split()
        l,r,c = int(s1[0]),int(s1[1]),int(s1[2])
        insert_c(b,l,r,c)
        m -= 1
    for i in range(1,n+1):
        b[i] += b[i-1]
        print(b[i],end=' ')
if __name__ == '__main__':
    main()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值