前缀和
前缀和:对于一个长度为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-3的sum = 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列表:
1 | 2 | 3 | 4 |
---|---|---|---|
5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 |
sum列表:
1 | 3 | 6 | 10 |
---|---|---|---|
6 | 14 | 24 | 36 |
15 | 33 | 54 | 78 |
28 | 60 | 96 | 136 |
下标从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统计子矩阵
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