2024年寒假算法班集训day05-知识总结及题解(前缀和与差分)

概念

前缀和与差分是解决数组区间问题的两种算法。

前缀和算法主要解决的是如何快速求得数组中一段区间的和。具体方法是先计算出数组的前缀和数组,其中第i个元素是原数组前i个元素的和。有了这个前缀和数组后,就可以快速求出任意区间的和了。例如,想要求原数组中从第l个到第r个元素的区间和,只需要用前缀和数组的第r个元素减去第l-1个元素的前缀和即可。

差分算法则用于当我们需要对数组的一个区间内的所有元素同时增加或减少一个值时。差分数组的第i个数表示原数组第i个元素与第i-1个元素的差值。通过差分,我们可以在常数时间内完成区间增减操作,再通过一次遍历来还原出修改后的原数组。

在实际应用中,前缀和可以用于统计区间的问题,比如求一个时间段内的访问量。差分则常用于需要频繁对区间数据进行增减的场景,比如多次添加或删除区间内的事件。二者结合使用,可以解决一些更复杂的数组操作问题。

1、计算区间和-2915
在这里插入图片描述
题目要求我们处理一个数组区间求和的问题。这是一道经典的前缀和算法题。前缀和算法的核心思想是预处理出一个数组,其中每一个元素s[i]代表原数组a[1]到a[i]的元素和。这样,任意区间[L,R]的和就可以通过s[R] - s[L-1]来快速获取。

具体到这道题,我们首先输入数组元素个数n和区间数m,然后输入n个整数存入数组a中。随后我们计算前缀和数组s,s[i] = s[i-1] + a[i]。这个过程中,s[0]可以初始化为0,因为没有元素的和自然是0。计算完前缀和数组后,我们就可以处理区间求和的问题了。

对于每个查询区间[L, R],我们只需输出s[R] - s[L-1]的值即可。这里s[L-1]代表的是数组a的第1个元素到第L-1个元素的和,而s[R]代表的是数组a的第1个元素到第R个元素的和。两者相减,自然就得到了第L个元素到第R个元素的和。

代码中的主要步骤如下:

  1. 输入整数个数n和区间数m。
  2. 循环输入n个整数,同时计算前缀和数组s。
  3. 对于每个查询区间[L, R],输出s[R] - s[L-1]。
#include<bits/stdc++.h>
using namespace std;
int main(){
   
	int n,m;
	int a[100001]={
   },s[100001]={
   };
	int L,R;
	cin>>n>>m;//n:元素个数 m:m组范围
	for(int i=1;i<=n;i++){
   
		cin>>a[i];     //先输入当前元素
		s[i]=s[i-1]+a[i];//再求当前位置的前缀和
	}
	for(int i=1;i<=m;i++){
   
		cin>>L>>R;//输入范围
		cout<<s[R]-s[L-1]<<endl;//输出范围上的元素和
	}
	return 0;
} 

这种方法的优点是能在O(1)的时间复杂度内快速求出任意区间的和,避免了重复计算,极大地提高了效率。因此,前缀和算法非常适合处理大量的区间求和查询。

2、侦察行动-2917
在这里插入图片描述
这道题目要求我们编写一个程序,它能够计算在一系列的战斗轮次中,敌方据点的总牢固值。这个问题可以用前缀和算法来高效解决。前缀和算法是通过事先计算一个数组的前缀和,来快速求解任意子数组和的方法。

具体步骤如下:

  1. 输入据点数量 n 和攻击轮数 m
  2. 输入每个据点的牢固值,并计算前缀和数组 s。前缀和数组 s[i] 表示从第一个据点到第 i 个据点的牢固值总和。
  3. 对于每一轮攻击,输入攻击范围的起始据点 L 和结束据点 R
  4. 计算并输出每轮攻击范围内据点的总牢固值,即 s[R] - s[L-1]。这是因为 s[R] 包含了从第一个据点到第 R 个据点的牢固值总和,而 s[L-1] 包含了从第一个据点到第 L-1 个据点的牢固值总和。两者之差就是从第 L 个据点到第 R 个据点的总牢固值。
#include<bits/stdc++.h>
using namespace std;
int main(){
   
	int n,m;
	int a[100001]={
   },s[100001]={
   };
	int L,R;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
   
		cin>>a[i];//输入据点牢固值
		s[i]=s[i-1]+a[i];//计算该据点前缀和
	}
	for(int i=1;i<=m;i++){
   
		cin>>L>>R;//输入一轮打击范围
		cout<<s[R]-s[L-1]<<endl;//输出一段范围的总牢固值
	}
	return 0;
}

这种算法的优势在于它避免了重复计算相同区间的和,使得即使在处理大量区间求和的问题时,也能保持高效的计算速度。通过预处理前缀和数组,每次计算区间和的时间复杂度降至 O(1),从而极大地提高了整个程序的效率。

3、K个元素和-2916
在这里插入图片描述
这个题目要我们求解一串数字中所有连续且长度为K的子序列的元素总和。为了高效计算这些子序列的总和,我们可以采用前缀和技巧。前缀和是一个非常实用的工具,它允许我们快速计算数组任意一段的和。

具体的做法如下:

  1. 初始化两个数组,a 用于存储输入的整数,s 用于存储这些整数的前缀和。前缀和 s[i] 表示从数组的开始到第 i 个元素为止所有元素的和。

  2. 输入整数个数 n 和子序列长度 K

  3. 逐个读入 n 个整数,并同时计算它们的前缀和存入数组 s

  4. 通过前缀和数组,我们可以计算任意长度为 K 的子序列的和,即 s[i] - s[i-K],其中 s[i] 是到第 i 个元素为止的和,而 s[i-K] 是到第 i-K 个元素为止的和。两者相减,就得到了第 i-K+1 到第 i 个元素的总和。

  5. 遍历数组 s,从第 K 个元素开始,计算每个长度为 K 的子序列的和,并输出。

这种方法的好处在于,一旦我们计算出了前缀和,那么任何长度为 K 的子序列的和都可以在常数时间内计算出来,大大提高了效率。

#include<bits/stdc++.h>
using namespace std;
  • 28
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值