1818 words
9 minutes
搞点Python778——day6

前缀和算法!启动!#

前缀和在我上学期刷蓝桥杯模拟的时候看到过,没有深入去了解算法,自己从字面上猜了一下,觉得思路很通畅。这一次系统地学习一下。

参考的博客:

1.超详细讲解前缀和

2.oi.wiki

3.迭代器

一维前缀和#

前缀和定义#

前缀和就是从位置1位置i这个区间内的所有的数字之和,是原始数组的元素依次累加的结果,用于高效地计算数组中某个范围内元素的和。

类似地可以定义前缀积与前缀异或和,但是应用并没有看到。

题目引入#

  • 输入一个长度为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

这就是一个非常典型的前缀和案例。设想一下如果我们用传统方式,代码的关键步骤:

sum = 0
for i in range(l,r+1):
	sum += ls[i]
print(sum)

除了这个循环,我们还需要对于m个询问进行循环。在计算过程中,我们就会发现,进行了很多次重复的计算,比如询问[2,5]与[3,7],中间[3,5]的部分我们是多次计算的。

因此我们就使用到前缀和的技术!对于数列表n,我们可以用列表s[i]记录n[0]~n[i]的所有数的和。显然:

if i == 0:
    a[i] = n[i]
else:
    a[i] = n[i] - n[i-1]

这跟高中学的数列也很像了。要从n列表计算s列表的话,我们可以用一下的代码:

s[0] = n[0] 
for i in range(1,num+1):
	s[i] = s[i-1] + n[i]

对于询问[l,r],我们可以用**s[r] - s[l-1]**一步到位计算,相比于之前的思路时间复杂度就降低了很多。

感谢oi.wiki!让我看到了Python的宝藏库——itertools!

迭代器itertools#

首先我们了解一下什么是惰性

  • 惰性:不主动去遍历它,就不会计算其中元素的值;
  • 惰性计算:包括延迟计算与短路求值。目的是要最小化计算机要做的工作;
  • 惰性序列:表达式和变量绑定后不会立即进行求值,而是当你用到其中某些元素的时候才去求某元素对的值。

在Python中,迭代器是常用来做惰性序列的对象。由于惰性,迭代器可以用来存储无限大的序列

迭代是 Python 最强大的功能之一,是访问集合元素的一种方式。可以被循环遍历的对象被称为可迭代对象,包括range()、列表对象等。

常用到的是使用列表构造迭代器,我们可以用iter()函数将列表转换为迭代器。例如:

ls = [1,2,3,4,5]
it = iter(ls)  #创建迭代器对象

而列表与迭代器的主要区别在于:

  • 列表不论遍历多少次,表头位置始终是第一个元素;
  • 迭代器遍历结束后,不再指向原来的表头位置,而是为最后元素的下一个位置

我们由编程验证:

for i in ls:
    print(i,end=' ')
print()
for i in ls:
    print(i,end=' ')
print()
for i in it:
    print(i,end=' ')
print()
for i in it:
    print(i,end=' ')
print()

会得到输出:

1 2 3 4 5 
1 2 3 4 5 
1 2 3 4 5 

第二次遍历it不会有任何结果,因为第一次遍历已经到了末尾。

Python的内置模块itertools就是用来操作迭代器的一个模块,其中函数主要分成以下三类:无限迭代器,有限迭代器,组合迭代器。

无限迭代器

用到的函数:

函数功能
count(start,step)创建一个迭代对象,生成从start开始的连续整数,步长为step
cycle(iterable)创建一个迭代对象,对于输入的iterable的元素反复执行循环操作
repeat(object[, times])创建一个迭代对象,重复生成object,次数为times,如果没有设置times,则会无线生成对象

编程效果如下:

from itertools import *
for i in count(2,4):
    if i == 18:
        break
    print(i,end=' ')
print()
f = 0
for i in cycle([1,2,3]):
    f += 1
    print(f"{i}:{f}")
    if f==3:
        break
for i in repeat("passion!",3):
    print(i)

输出结果如下:

2 6 10 14 
1:1
2:2
3:3
passion!
passion!
passion!

有限迭代器/输入序列迭代器

函数如下:

函数功能
accumulate(iterable [,func])创建一个迭代对象,由特定的二元函数的累计结果生成,默认进行进行累加操作(就是我们需要的前缀和)
chain(*iterables)创建一个迭代对象,多个可迭代对象组合起来,形成一个更大的迭代器。

先学到这里吧,感觉就这几个能用上。

iterable与*iterables的区别在于iterable是可迭代对象,如列表、range()等;而*iterables是多个可迭代对象。【个人感觉,也不是很准确】

编程感受:

#前缀和
for i in accumulate(range(1,5)):
    print(i,end= ' ')
print()
#前几项中最大的数字
for i in accumulate([2,1,3,8,4,6],max):
    print(i,end = ' ')
print()
#将两个可迭代对象组合起来
for i in chain([1,4],"dsfe"):
    print(i,end=' ')

得到输出如下:

1 3 6 10 
2 2 3 8 8 8 
1 4 d s f e 

组合迭代器

函数如下:

函数功能
product(*iterables, repeat=1)创建一个迭代对象,返回多个可迭代对象的笛卡儿积,repeat 参数表示这些可迭代序列重复的次数)
permutations(iterable,r)创建一个迭代对象,以元组形式返回可迭代对象中元素的排列。r默认为None,表示的是返回元组的长度
combinations(iterable,r)创建一个迭代对象,以元组形式返回可迭代对象中元素的组合。r默认为None,表示的是返回元组的长度
combinations_with_replacement(iterable, r)创建一个迭代对象,以元组形式返回可迭代对象中可与自身重复的元素的组合。r默认为None,表示的是返回元组的长度

编程感受:

for i in product([1,2],[3,4]):
    print(i, end=' ')
print()
for i in permutations([1,2,3],2):
    print(i,end=' ')
print()
for i in combinations([1,2,3],2):
    print(i,end=' ')
print()
for i in combinations_with_replacement([1,2,3],2):
    print(i,end=' ')

得到输出:

(1, 3) (1, 4) (2, 3) (2, 4) 
(1, 2) (1, 3) (2, 1) (2, 3) (3, 1) (3, 2) 
(1, 2) (1, 3) (2, 3) 
(1, 1) (1, 2) (1, 3) (2, 2) (2, 3) (3, 3) 

使用accumulate完成习题#

编程实现:

from itertools import *
import sys
input = lambda:sys.stdin.readline().strip()
n,m = map(int,input().split())
#数列表
ls = list(map(int,input().split()))
#前缀和列表,注意这里有个添加0的处理
s = list(chain([0],list(accumulate(ls))))
for i in range(m):
    l,r = map(int,input().split())
    print(f"{s[r] - s[l-1]}")

ok因为有一个新的模块,这篇博客就到这里吧!下一次就上二维的!

搞点Python778——day6
https://ryuhana.netlify.app/posts/prefix-sum/prefix_sum/
Author
Ryuhana
Published at
2025-02-28