前缀和与差分的概述和应用(非常简单,一看就会)

1、 一维前缀和

简单来说前缀和是指某序列的前n项和,就跟高等数学里的数列的前 n n n 项和一样。
举个例子:
B[5] = 1 2 3 4 5
A[5] = 1 3 6 10 15
那么A数组称为B数组的前缀和。很简单对吧

2、应用

快速求出元素组中某段区间的和

3、例子

795.前缀和

输入一个长度为 n n n 的整数序列。
接下来再输入 m m m 个询问,每个询问输入一对 l , r l,r l,r
对于每个询问,输出原序列中从第 l l l 个数到第 r r r 个数的和。

输入格式

第一行包含两个整数 n n n m m m
第二行包含 n n n 个整数,表示整数数列。
接下来 m m m 行,每行包含两个整数 l l l r r r,表示一个询问的区间范围。

输出格式

m m m 行,每行输出一个询问的结果。

数据范围

1 ≤ l ≤ r ≤ n , 1≤l≤r≤n, 1lrn,
1 ≤ n , m ≤ 100000 , 1≤n,m≤100000, 1n,m100000,
− 1000 ≤ 数 列 中 元 素 的 值 ≤ 1000 −1000≤数列中元素的值≤1000 10001000

输入样例:

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

输出样例:

3
6
10

思路:

只要将前缀和数组初始化一下,然后根据询问的下标,拿两个数相减就可以了。(注意越界问题。一般从1下标开始取值和赋值

代码:

# 前缀和模板
N = 100010
n,m=map(int,input().split())
a=[0]*N
s=[0]*N
a[1:n+1] = list(map(int,input().split()))
# 这一步是关键,初始化前缀和S
for i in range(1,n+1):
    s[i] = s[i-1] + a[i]
while m:
    l,r=map(int,input().split())
    # 注意下标问题,为防止越界问题,一般都是从1下标开始取值和赋值
    print(s[r] - s[l-1])
    m -= 1

4、一维差分

简单来说:差分可以看成前缀和的逆运算。
我们再拿上面的例子来说,只不过把A和B的位置换了一下。
例子:
A[5] = 1 3 6 10 15
B[5] = 1 2 3 4 5
那么A数组称为B数组的前缀和。和前面一样对吧,那么B数组就称为A数组的差分
其实通过上面一个例子,很容易得出差分数组B的规律:
B[i] = A[i] - A[i-1]
当然你需要考虑下标问题,建议取值和赋值的时候是从下标1开始的,下标为0的数就初始化为0

5、应用

快速使得元素组中某段区间的数加上一个常数

6、例子

797.差分

输入一个长度为 n n n 的整数序列
接下来输入 m m m 个操作,每个操作包含三个整数 l , r , c l,r,c l,r,c,表示将序列中 [ l , r ] [l,r] [l,r] 之间的每个数加上 c c c
请你输出进行完所有操作后的序列。

输入格式

第一行包含两个整数 n n n m m m
第二行包含 n n n 个整数,表示整数序列。
接下来 m m m 行,每行包含三个整数 l , r , c l,r,c lrc,表示一个操作。

输出格式

共一行,包含 n n n 个整数,表示最终序列。

数据范围

1 ≤ n , m ≤ 100000 , 1≤n,m≤100000 , 1n,m100000,
1 ≤ l ≤ r ≤ n , 1≤l≤r≤n, 1lrn,
− 1000 ≤ c ≤ 1000 , −1000≤c≤1000, 1000c1000,
− 1000 ≤ 整 数 序 列 中 元 素 的 值 ≤ 1000 −1000≤整数序列中元素的值≤1000 10001000

输入样例:

6 3
1 2 2 1 2 1
1 3 1
3 5 1
1 6 1

输出样例:

3 4 5 3 4 2

思路:

这个性质要记住:
A A A B B B 的前缀和数组,那么对 B B B 数组的 B [ i ] B[i] B[i] 修改,会影响到 A A A 数组中从 A [ i ] A[i] A[i] 及之后的每一个数。

理解了上面这条性质,就理解了差分,这个题目就很简单了。
我们只需要对 B [ l ] B[l] B[l] += c c c ,这样 A [ l ] A[l] A[l] 及之后的每一个数都会加上 c c c
我们再进行 B [ r + 1 ] B[r+1] B[r+1] —= c c c ,这样 A [ r + 1 ] A[r+1] A[r+1] 及之后的每一个数都会减去 c c c
这样我们就完成了对区间 [ l , r ] [l,r] [l,r] 的数加 c c c注意越界问题。一般从1下标开始取值和赋值

代码:

# 差分模板
N = 100010
a = [0]*N
b = [0]*N
# 对区间[l,r]的数加上常数c
def insert(l,r,c):
    b[l] += c
    b[r+1] -= c

n,q=map(int,input().split())
a = [0] + list(map(int,input().split()))
# 构造差分数组b
for i in range(1,n+1):
    insert(i,i,a[i])

# 读入操作
while q:
    l,r,c = map(int,input().split())
    insert(l,r,c)
    q -= 1

# 求差分数组b的前缀和即可得到数组a
for i in range(1,n+1):
    b[i] += b[i-1]

# 输出结果
for j in range(1,n+1):
    print(b[j],end=" ")

总结:

一维前缀和、一维差分都是很简单的,在比赛中,背下来关键步骤即可。至于二维前缀和、二维差分只不过是从一维数据变到了二维数据罢了,也就是矩阵。画个图也很容易理解。这里不再赘述了。
(ps:为了方便,一般从下标1开始取值和赋值。)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值