前缀和-二维前缀和

前缀和

前缀和:对于一个长度为n的列表a,前缀和为:

sum[i] = a[0] + a[1] + …+ a[i]
例如a = [1,3,4,2,5],前缀和数组sum = [1,4,8,10,15]

前缀和性质:

①sum[i] = sum[i-1] + a[i]
②a[l] + … + a[r] = sum[r] - sum[l-1]

性质①用于处理前缀和
性质②可以在o(1)时间内求出区间l到r的区间和

前缀和的实现

法1:自己写函数

#求列表a的前缀和
def get_presum(a):
    n = len(a)
    sum = [0] * n
    sum[0] = a[0]
    for i in range(1,n):
        sum[i] = sum[i-1] + a[i]
    return sum#返回前缀和列表

#求区间l到r的前缀和(a[l]到a[r])
def get_sum(sum , l , r):
    if l == 0:
        return sum[r]
    else:
        return sum[r] - sum[l - 1]


a = [1,2,3,4,5]
sum = get_presum(a)
print("a = " , a)
print("pre_sum = " , sum)
print("区间2-3的sum = " , get_sum(sum , 2 , 3))
#注:此时区间2-3是列表a中的下标,即a[2]=3   a[3]=4的和

法2:from itertools import accumulate

from itertools import accumulate
#求列表a的前缀和
def get_presum(a):

    sum = list(accumulate(a))

    return sum#返回前缀和列表

#求区间l到r的前缀和(a[l]到a[r])
def get_sum(sum , l , r):
    if l == 0:
        return sum[r]
    else:
        return sum[r] - sum[l - 1]


a = [1,2,3,4,5]
sum = get_presum(a)
print("a = " , a)
print("pre_sum = " , sum)
print("区间2-3的sum = " , get_sum(sum , 2 , 3))
#注:此时区间2-3是列表a中的下标,即a[2]=3   a[3]=4的和


运行结果

a =  [1, 2, 3, 4, 5]
pre_sum =  [1, 3, 6, 10, 15]
区间2-3sum =  7

3382区间次方和

题目链接:3382区间次方和
区间次方和

from itertools import accumulate
mod  = 1000000007
def get_presum(a):
    sum = list(accumulate(a))
    sum = [x % mod for x in sum]
    return sum#返回前缀和列表

#求区间l到r的前缀和(a[l]到a[r])
def get_sum(sum , l , r):
    if l == 0:
        return sum[r]
    else:
        return (sum[r] - sum[l - 1] + mod) % mod

n , m = map(int , input().split())
a = list(map(int , input().split()))
sum_lst = []
#此处为o(n)时间提前生成5个列表,每个列表是x的i次方
for i in range(1,6):
    sum_lst.append(get_presum([x**i for x in a]))
#print("sum_lst:",sum_lst)
for i in range(m):
    l , r , k = map(int , input().split())
    print(get_sum(sum_lst[k - 1] , l - 1 , r - 1))

运行结果

5 3
1 2 3 4 5
sum_lst: [[1, 3, 6, 10, 15], [1, 5, 14, 30, 55], [1, 9, 36, 100, 225], [1, 17, 98, 354, 979], [1, 33, 276, 1300, 4425]]
1 3 2
14
2 4 3
99
3 5 1
12

如果在m次循环中,每次按照k的输入生成次方数组,提交代码会时间超时

3419小郑的蓝桥平衡串

题目链接:3419小郑的蓝桥平衡串

from itertools import accumulate
#求列表a的前缀和
def get_presum(a):
    sum = list(accumulate(a))
    return sum#返回前缀和列表

#求区间l到r的前缀和(a[l]到a[r])
def get_sum(sum , l , r):
    if l == 0:
        return sum[r]
    else:
        return sum[r] - sum[l - 1]

s = input()
n = len(s)
a = []
for x in s:
    if x == 'L':
        a.append(1)
    else:
        a.append(-1)
sum = get_presum(a)
# print("a:",a)
# print("sum:",sum)
ans = 0
#遍历,从0到n-1子序列有无平衡串,若有则比较大小保留当前平衡串最大长度;
# 再遍历1到n-1子序列有无平衡串....
for i in range(n):
    for j in range(i,n):
        #print("i:{},j:{},get_sum:{}\n".format(i,j,get_sum(sum , i , j)))
        if get_sum(sum , i , j) == 0:
            ans = max(ans , j - i + 1)
            #print("j{} - i{} + 1={}".format(j,i,j-i+1))
print(ans)

运行结果

LQLL
2

二维前缀和

对于n*m的二维列表a(下标从1开始),前缀和为:

sumxy = ∑ i = 1 x \sum_{i=1}^x i=1x ∑ j = 1 y \sum_{j=1}^y j=1yaij

a列表:

1234
5678
9101112
13141516

sum列表:

13610
6142436
15335478
286096136

下标从1,1开始,有如下统一公式:

sumi,j = sumi-1,j +sumi,j-1 -sumi-1,j-1 +ai,j
例如14 = 3+6-1+6

二维前缀和的实现

def output(a,n):
    for i in range(1,n+1):
        print(" ".join(map(str,a[i][1:])))
    print()

n , m = map(int,input().split())
#下标从1开始
a = [ [0]*(m+1) for i in range(n+1) ]
sum = [ [0]*(m+1) for i in range(n+1) ]

#输入一个二维数组
for i in range(1,n+1):
    a[i] = [0] + list(map(int,input().split()))
output(a,n)

for i in range(1,n+1):
    for j in range(1,n+1):
        sum[i][j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]
output(sum,n)

运行结果

4 4
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16

1 3 6 10
6 14 24 36
15 33 54 78
28 60 96 136

(x1,y1)-(x2,y2)之和=sumx2,y2 -sumx1-1,y2 -sumx2,y1-1 +sumx1-1,y1-1

二维前缀和示例

2109统计子矩阵

题目链接:2109统计子矩阵
2109统计子矩阵

def get_sum(sum,x1,y1,x2,y2):
    return sum[x2][y2] - sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1]


n , m , k = map(int,input().split())
#下标从1开始
a = [ [0]*(m+1) for i in range(n+1) ]
sum = [ [0]*(m+1) for i in range(n+1) ]
#输入一个二维数组
for i in range(1,n+1):
    a[i] = [0] + list(map(int,input().split()))
#求二维前缀和
for i in range(1,n+1):
    for j in range(1,m+1):
        sum[i][j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]
ans = 0
for x1 in range(1,n+1):
    for y1 in range(1,m+1):
        for x2 in range(x1,n+1):
            for y2 in range(y1,m+1):
                if get_sum(sum,x1,y1,x2,y2)<=k:
                    ans += 1
print(ans)

运行结果

3 4 10
1 2 3 4
5 6 7 8
9 10 11 12
19

参考链接:https://blog.csdn.net/Charlie482/article/details/136317531

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

唐丶晚笙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值