十一.前缀和
一维
如果有一个长度为n的数组,前缀和数组Si表示为原数组中前i个数组的和。
注意前缀和中下标一定要从1开始。
1.如何求Si
①用for循环从i=1开始,S[i]=S[i-1]+a[i]
2.求Si的作用:可以快速的求出原数组中一段数的和。
二维(子矩阵的和)
S[i,j]的含义:从第1行到第i行的前j列的和。
1.如何去算?
一行行的去算。
S[i,j]=S[i-1,j]+S[i,j-1]-S[i-1,j-1]+a[i,j]可以画图思考,其中减去的部分是被加了两次的部分。
2.如果要求求以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵的和,该如何去求?
①其总和为:S[x2,y2]-S[x1-1,y2]-S[x2,y1-1]+S[x1-1,y1-1]
此处可以画图理解,就是先算出大矩阵,然后减掉了两个小矩阵,最后加上一次 两次减法重合减去的部分
差分(前缀和的逆运算)
已知数组a,要求构造一个数组b,使得a[i]=b[1]+b[2]+……+b[i]
构造b[1]=a[1],则b[2]=a[2]-a[1]……b[n]=a[n]-a[n-1]
运用:
比如说一个题目要求把一个数组中[l,r]区间的数都加上C,如果用循环遍历时间复杂度为O(n),如果用拆分的话,构造完b,把b[l]加上C,再算a相当于a从l开始自动加上了C,时间复杂度为O(1),然后再让b[r+1]-C即可。
基于这个运用,也可以这样想:假设原数组a从1到n都为0,而实际上从[1,1]到[n.n]区间,每个区间都分别“插入”了a[1],a[2]……a[n],这样反推构造数组b,其实就相当于不用考虑如何去构造b了,详情见代码
给出一个数组长度n,接下来有m行,每行包括3个数据,分别shi l,r,c表示要在区间[l,r]中的每个数加上c
#include<iostream>
using namespace std;
const int N=10010;
int n,m;
int a[N].b[n];
void insert(int l,int r,int c){//负责插入的函数
b[l]+=c;
b[r+1]-=c;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scnaf("%d",&a[i]);
for(intg i=1;i<=n;i++) insert(i,i,a[i]);//这里是运用了加粗字体部分的思想正在构造差分数组b
while(m--){
int l,r,c;
scanf("%d%d%d",&l,&r,&c);
insert(l,r,c);
}
for(int i=1;i<=n;i++) b[i]+=b[i-1];//这里是为了把b数组变为自身的前缀和数组
for(int i=1;i<=n;i++) printf("%d",b[i]);
}
二维差分(差分矩阵)
暂略