这次简单聊一下一维的前缀和和差分
一、前缀和和差分是什么?
前缀和:
前缀和(Prefix Sum)是指一个数组从第一个元素到当前元素的所有元素的累加和。具体来说,对于给定的一个数组 A,其前缀和数组 S 的计算公式为:S[i]=A[0]+A[1]+⋯+A[i]
其中,S[0]=0 是为了便于后续区间计算。例如,如果有一个数组 nums=[1,2,3,4],那么它的前缀和数组就是 [0,1,3,6,10] 。
前缀和的主要优点在于能够快速计算任意区间的和,而不需要遍历整个区间内的所有元素。这大大降低了时间复杂度,常用于解决子数组最大和、区间求和等问题。
编辑
差分:
差分(Difference)是前缀和的逆运算。它主要用于快速对数组的某一个区间每个数加上或减去一个常数。差分的结果反映了离散量之间的一种变化,是研究离散数学的一种工具。具体来说,如果有一个原数组,其差分数组b[] 的计算公式为:b[i]=a[i+1]−a[i]
这样,通过差分可以将原数组中的某些操作简化为简单的加减运算。
差分的主要作用是快速修改数组中某一区间的值,并且可以用来恢复原数组的状态。例如,在需要频繁更新数组某一区间内元素值的情况下,使用差分可以显著提高效率。
编辑
总之:前缀和解决求一个数据范围内某段l-r的数据的和 ,差分解决数组中对某一范围数据l-r进行批量加减
二、模版与使用
1.模版
前缀和和差分的模版主要是数学公式,记住就好
前缀和:
创建前缀和数组:s[i]=s[i-1]+a[i]
求l到r总和的大小: s[r]-s[l-1]
差分:
创建差分数组:b[i]=a[i]-a[i-1]
批量加减操作公式:b[l]+=c,b[r+1]-=c;
2.示例
前缀和:
输入一个长度为 n的整数序列。
接下来再输入 m 个询问,每个询问输入一对 l,r,。
对于每个询问,输出原序列中从第 l个数到第 r 个数的和。
输入格式
第一行包含两个整数 n 和 m。
第二行包含 n 个整数,表示整数数列。
接下来 m行,每行包含两个整数 l和 r,表示一个询问的区间范围。
输出格式
共 m 行,每行输出一个询问的结果。
输入样例:
5 3
2 1 3 6 4
1 2
1 3
2 4
输出样例:
3
6
10
#include<iostream>//导入库
using namespace std;
const int N=1e5+10;
int a[N],s[N];
int n,m;
int main()
{
cin>>n>>m;
s[1]=0;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);//读入数据
for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];//创建差分数组
while(m --)
{
int l,r;
cin>>l>>r;//读入要求的数组范围
printf("%d\n", s[r]-s[l-1]);//求l-r的数据总和
}
return 0;
}
差分:
输入一个长度为 n的整数序列。
接下来输入 m个操作,每个操作包含三个整数 l,r,c表示将序列中 [l,r]之间的每个数加上c。
请你输出进行完所有操作后的序列。
输入格式
第一行包含两个整数 n 和 m。
第二行包含 n个整数,表示整数序列。
接下来 m行,每行包含三个整数 l,r,c表示一个操作。
输出格式
共一行,包含 n个整数,表示最终序列。
输入样例:
6 3
1 2 2 1 2 1
1 3 1
3 5 1
1 6 1
输出样例:
3 4 5 3 4 2
#include<iostream>
using namespace std;
const int N=1e5+10;
int a[N],b[N];
int n,m;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i]-a[i-1];//创建差分数组
}
while(m --)
{
int l,r,c;
scanf("%d%d%d",&l,&r,&c);
b[l]+=c;//进行差分操作
b[r+1]-=c;
}
for(int i=1;i<=n;i++) printf("%d ",a[i]=b[i]+a[i-1]);//还原数组
return 0;
}
三 、 例题
优秀的算法能力离不开大量的练习,下面推荐几道例题供大家练习
一.洛谷P8772 [蓝桥杯 2022 省 A] 求和
二.洛谷B3628 机器猫斗恶龙
三.洛谷P4702 取石子