精华内容
下载资源
问答
  • 二维前缀和

    2019-06-22 16:28:06
    二维前缀和

    二维前缀和

    在这里插入图片描述

    展开全文
  • 二维差分与二维前缀和

    千次阅读 2020-12-14 20:20:30
    二维差分和二维前缀和息息相关 二维前缀和很好定义: 但差分很不直观,要用前缀和的逆运算的特点推 那么假设每个点的差分值是 ci,j ,而我们知道一维差分的前缀和即为当前点的值,那么二维差分也不例外。所以二维...

    二维差分

    二维差分和二维前缀和息息相关

    二维前缀和很好定义:
    在这里插入图片描述
    但差分很不直观,要用前缀和的逆运算的特点推
    在这里插入图片描述
    在这里插入图片描述
    那么假设每个点的差分值是 ci,j ,而我们知道一维差分的前缀和即为当前点的值,那么二维差分也不例外。所以二维差分的前缀和即为ai,j 。那么从上面这个公式引导下来
    在这里插入图片描述
    那么由差分值推导到前缀和(也就是推导到当前点的值)便也和简单,上面这个公式移一下项即可

    ai,j = ai,j-1 + ai-1,j - ai-1,j-1 + ci,j

    应用

    那么一维差分可以用于区间加减,那么二维差分呢,那当然也是可以的,只不过是一个二维的区间。

    在这里插入图片描述
    在我们要的区间开始位置(x1,y1)处 +x,根据前缀和的性质,那么它影响的就是整个黄色部分,多影响了两个蓝色部分,所以在两个蓝色部分 -x 消除 +x 的影响,而两个蓝色部分重叠的绿色部分多了个 -x 的影响,所以绿色部分 +x 消除影响。所以对应的计算方法如下:

    1.c[x1][y1]+=x
    2.c[x1][y2+1]-=x
    3.c[x2+1][y1]-=x
    4.c[x2+1][y2+1]+=x
    

    有些引用了大佬

    https://blog.csdn.net/justidle/article/details/104506724

    的博客,大家可以去围观。

    展开全文
  • 前缀和、二维前缀和与差分的小总结

    万次阅读 多人点赞 2018-08-17 16:21:35
    在了解二维前缀和之前,我们首先需要了解一下什么是前缀和。 如果我给你一串长度为n的数列a1,a2,a3......an,再给出m个询问,每次询问给出L,R两个数,要求给出区间[L,R]里的数的和,你会怎么做,若是没有了解过前缀...

    在了解二维前缀和之前,我们首先需要了解一下什么是前缀和。

    如果我给你一串长度为n的数列a1,a2,a3......an,再给出m个询问,每次询问给出L,R两个数,要求给出区间[L,R]里的数的和,你会怎么做,若是没有了解过前缀和的人看到这道题的想法可能是对于m次询问,我每次都遍历一遍它给的区间,计算出答案,这样子的方法固然没错,但是其时间复杂度达到了O(n*m),如果数据量稍微大一点就有可能超时,而我们如果使用前缀和的方法来做的话就能够将时间复杂度降到O(n+m),大大节省了运算时间。至于怎么用,请看下面一小段代码

    a[0]=0;
    
    for(int i=1;i<=n;i++)a[i]+=a[i-1];

    没错,前缀和顾名思义就是前面i个数的总和。数组a在经过这样的操作之后,对于每次的询问,我们只需要计算a[R]-a[L-1]就能得到我们想要的答案了,是不是很简单呢。

    在知道了最简单的前缀和之后,我们再来了解一下什么是差分。

    给你一串长度为n的数列a1,a2,a3......an,要求对a[L]~a[R]进行m次操作:

    操作一:将a[L]~a[R]内的元素都加上P

    操作二:将a[L]~a[R]内的元素都减去P

    最后再给出一个询问求a[L]-a[R]内的元素之和?

    你会怎么做呢?你可能会想,我对于m次操作每次都遍历一遍a[L]~a[R],给区间里的数都加上P或减去P,最后再求一次前缀和就行了。没错,这样子确实也能得出正确答案,但时间复杂度却高达O(M*n),对于1<=n,m<=1e5这个数据范围来说直接就tle了,所以说这个方法不可行。既然这样不行的话,那我们要怎么做才能快速的得到正确答案呢?是的,这个时候我们的差分就该派上用场了,我们新开一个数组b,储存每一次的修改操作,最后求前缀和的时候统计一下就能快速的得到正确答案了,详细请看下面代码。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+9;
    int a[maxn],b[maxn];
    int main(){
    	int i,j,k,n,m,p;
    	cin>>n>>m;
    	for(i=1;i<=n;i++){
    		cin>>a[i];
    	}
    	for(i=1;i<=m;i++){
    		int L,R,t;
    		cin>>t>>L>>R>>p;
    		if(t==1){
    			b[L]+=p;b[R+1]-=p; //仔细想想为什么b[R+1]要减去p 
    		}
    		else{
    			b[L]-=p;b[R+1]+=p;
    		}
    	}
    	int add=0;
    	for(i=1;i<=n;i++){
    		add+=b[i];
    		a[i]+=a[i-1]+add;
    	}
    	int x,y;
    	cin>>x>>y;
    	cout<<a[y]-a[x-1]<<endl;
    }

    相信看到这里,大家已经仔细思考过代码了,为什么操作一时b[R+1]要减去p,很简单,因为操作一我只需对[L,R]区间里的数加p,[R+1,n]这个区间里的数没必要加p,所以需要减掉p。

    差分讲解完毕,接下来我们终于要开始今天的正题——二维前缀和了。

    还是以小问题的形式来讲解二维前缀和吧。

    给定一个n*m大小的矩阵a,有q次询问,每次询问给定x1,y1,x2,y2四个数,求以(x1,y1)为左上角坐标和(x2,y2)为右下角坐标的子矩阵的所有元素和。注意仍然包含左上角和右下角的元素。

    怎么做呢?为了方便你们理解,我画个图吧。

    图画的很丑,希望不要介意。如图所示,按题目要求,我们每次要求的答案就是红色圆圈所在的区域的值(注意,这里的x1,x2表示行,y1,y2表示列),对比上面这张图我们能够发现红色区域的值等于四个区域的值减去(白色区域+黑色区域),再减去(白色区域+蓝色区域),最后因为白色区域被减了两次,我们需要再加回来。所以ans=a[x2][y2]-a[x1-1][y2]-a[x2][y1-1]+a[x1-1][y1-1];(注意,此时的a数组代表的是前缀和)。突然想起来还没说怎么求二维前缀和,很简单,看下面代码。

    for(int i=1;i<=n;i++){
    	for(int j=1;j<=m;j++)
    	a[i][j]+=a[i][j-1]+a[i-1][j]-a[i-1][j-1];
    } 

    为方便理解贴个图

    假如我想求a[2][4]的前缀和,我得先加上a[1][4]的前缀和,再加上a[2][3]的前缀和,然后这个时候我们发现实际上a[1][3]这个部分我们加了两遍,所以我们需要再减去一遍a[1][3],于是得出公式a[i][j]+=a[i][j-1]+a[i-1][j]-a[i-1][j-1]

    接下来看完整代码吧。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e3+9;
    int a[maxn][maxn];
    int main(){
    	int i,j,k,n,m,q;
    	cin>>n>>m>>q;
    	for(i=1;i<=n;i++){
    		for(j=1;j<=m;j++)
    		cin>>a[i][j];
    	}
    	for(i=1;i<=n;i++){
    		for(j=1;j<=m;j++)
    		a[i][j]+=a[i][j-1]+a[i-1][j]-a[i-1][j-1];
    	}
    	for(i=1;i<=q;i++){
    		int x1,y1,x2,y2;
    		cin>>x1>>y1>>x2>>y2;
    		int ans=a[x2][y2]-a[x1-1][y2]-a[x2][y1-1]+a[x1-1][y1-1];
    		cout<<ans<<endl;
    	}
    }

    是不是感觉很简单呢,哈哈哈哈哈哈哈。

    在学完二维前缀和之后,一些同学可能会有疑问,一维前缀和能用上差分,那么二维前缀和能不能用上差分呢?答案是肯定的。

    那么怎么差分呢?方法是和一维类似的,我们也是需要另开一个数组记录修改操作,最后求前缀和时统计修改操作,只是二维每一次操作需要记录4个位置,一维只需要记录2个位置。具体怎么做,看下面代码吧。

    for(int i=0;i<m;i++){//m是修改操作次数 
    	int x1,y1,x2,y2,p;
    	cin>>x1>>y1>>x2>>y2>>p;
    	b[x1][y1]+=p;b[x2+1][y2+1]+=p;
    	b[x2+1][y1]-=p;b[x1][y2+1]-=p;
    }

    好了,一维前缀和、二维前缀和、差分都说完了,希望看这篇文章的人能够有所收获吧。

    展开全文
  • 二维前缀和详解

    万次阅读 多人点赞 2018-09-22 16:46:59
    这几天在打比赛时遇到了二维前缀和,看了一下深有体会,发一篇详解。 首先,什么是前缀和?一个数列,我们要计算某个区间内的和,该怎么做呢?正所谓暴力出奇迹,这一个也可以,我们暴力枚举每一个区间内的数并且...

    这几天在打比赛时遇到了二维前缀和,看了一下深有体会,发一篇详解。
    首先,什么是前缀和?一个数列,我们要计算某个区间内的和,该怎么做呢?正所谓暴力出奇迹,这一个也可以,我们暴力枚举每一个区间内的数并且相加,可是这个是O(n)的时间复杂度,不要小看这个线性,可如果在DP里的话这相当于加了一次方,卡你非常简单,下面讲一下O(n)的预处理,O(1)的计算,你可能会说这个也是线性,有差吗?当然有差,这个是需处理,不会像暴力一样在DP中使DP的时间复杂度加一次方而是直接加上O(n)。下面讲一下做法,前缀和,顾名思义就是第几个数之前的数的和,我们用DP来预处理,我们定义状态DP[i]表示到第i个数(包括它)为止前面所有数的和,从而得出状态转移方程DP[i]=DP[i-1]+num[i],num[i]表示数组中第i个数,这样要计算闭区间i,j(闭区间就是指i<=x<=j,x就是区间里的数)的和就是DP[j]-DP[i-1],这个画图理解如下:在这里插入图片描述
    下面我们讲一下什么是二维前缀和,建立在一维前缀和之上,我们要求一个矩阵内一个任意的子矩阵的数的和,我们就可以用二维前缀和,我们还是用DP来预处理,状态和一维前缀和差不多,只不过我们多加了一维,DP[i][j]表示(1,1)这个点与(i,j)这个点两个点分别为左上角和右下角所组成的矩阵内的数的和,好好想一下状态转移方程,DP[i][j]=DP[i-1][j]+DP[i][j-1]-DP[i-1][j-1]+map[i][j],怎么来的呢?我们画一下图就知道了。
    在这里插入图片描述
    这张图就知道了(i,j)可以由(i-1,j)和(i,j-1)两块构成,不过要注意两个点,1、有一块矩阵我们重复加了,也就是(i-1,j-1)这一块,所以我们要减去它。2、我们这个矩阵是不完整的,由图可知我们还有一块深蓝色的没有加,也就是(i,j)这一点,所以我们要再加上map[i][j]也就是题目给出的矩阵中这一格的数。这样我们就预处理完了,现在讲一下怎么通过我们的预处理从而快速地得出我们想要的任意子矩阵中的和,我们定义(x1,y1)为我们想要子矩阵的左上角,(x2,y2)为我们想要子矩阵的右下角,然后我们画图想一想。
    在这里插入图片描述
    我们可以通过DP[x2][y2]来计算,我们通过图可以发现这个距离我们要的还差红色的部分看看怎么表示红色部分?我们可以分割成两块,分别是DP[x1][y2]和DP[x2][y1]我们发现有一块重复减了,所以我们再加上它即DP[x1][y1],有一点注意,因为画图和定义原因我们发现边界好像不对,我们来看看,我们定义的状态是整个矩阵包括边的和,而我们要求的也是要包括边的,所以我们要再改一下,把DP[x1][y2]和DP[x2][y1]和DP[x1][y1]分别改成DP[x1-1][y2]和DP[x2][y1-1]和DP[x1-1][y1-1]这样一减我们就可以得到自己想要的答案,整理可得公式,DP[x2][y2]-DP[x1-1][y2]-DP[x2][y1-1]+DP[x1-1][y1-1]这样我们就可以做到O(1)之内查询,很奇妙吧,我们看一下实现代码:

    #include<iostream>
    #include<cstring>
    using namespace std;
    int dp[2000][2000],map[2000][2000];
    int main()
    {
    	int m,n,k;//所给的矩阵是n*m的,有k组查询 
    	cin >>n>>m>>k;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			cin >>map[i][j];
    	memset(dp,0,sizeof(dp));
    	for(int i=1;i<=n;i++)//预处理一波 
    		for(int j=1;j<=m;j++)
    			dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+map[i][j];
    	for(int i=1;i<=k;i++)//接受查询 
    	{
    		int x1,x2,y1,y2;
    		cin >>x1>>y1>>x2>>y2;
    		cout <<(dp[x2][y2]+dp[x1-1][y1-1]-dp[x1-1][y2]-dp[x2][y1-1])<<endl;//O(1)查询 
    	}
    	return 0;
    } 
    

    这样二维前缀和就讲完了,下面给一个不错的例题:
    模板题
    给一下题解:弱鸡写的题解
    希望这一篇算法解析对大家有帮助。

    展开全文
  • 二维前缀和 二维前缀和公式: sum[x2][y2]=b[x2][y2] + sum[x2][y1-1] + sum[x1-1][y2] - sum[x1-1][y1-1] 算法思路:创立数组sum[ ][ ],sum[i][j]表示ij坐标左上角全部数的总和(包括i,j),求x1,y1,x2,y2这个...
  • 二维前缀和 模板

    2021-07-12 21:21:41
    一、介绍: 【一维前缀和】 一维前缀和顾名思义 就是一维的前缀和 前缀和是什么呢? 前缀和就是到目前为止全部的和是多少 一维就是单纯的一串数 他的前缀和就成了一维前缀和 ...那二维前缀和中一个f[i][...
  • 【LeetCode】﹝前缀和ி﹞一维、二维前缀和应用

    千次阅读 多人点赞 2021-05-31 09:12:12
    【LeetCode】﹝前缀和ி﹞一维、二维前缀和应用 文章目录【LeetCode】﹝前缀和ி﹞一维、二维前缀和应用在区间范围内统计奇数数目★区域和检索 - 数组不可变★★子数组异或查询★★定长子串中元音的最大数目★★生存...
  • 前缀和与二维前缀和

    2021-08-03 09:49:58
    二维前缀和 一维数组能对其求前缀和,那么二维矩阵也能对其求前缀和! 如果我们想求红色矩阵内的元素值,可以发现同样可以通过前缀和相减获得 那么如何求前缀和呢?? s[i][j]=g[i][j]+s[i-1][j]+s[i][j-1]-s[i-
  • 差分 一维差分 二维差分 差分数组意义 前缀和 一维前缀和 二维前缀和 最大难点在于 二维差分数组的理解 二维差分数组d[x][y] 不是指 a数组中具体某两个值的差值. d数组用于统计二维矩阵值的更新,是我告诉你某...
  • 二维前缀和

    2020-08-22 23:08:20
    二维前缀和 南昌理工学院ACM集训队 ???? 给你一个二维平面,要求它的区间和,怎么办呢? 正所谓“暴力出奇迹”,我们当然可以枚举每一个区间的数然后相加,但是聪明的孩子就会开始思考,既然一维数组存在区间和的...
  • 前缀和&二维前缀和

    2019-06-29 10:26:00
    那么,怎样求二维前缀和呢? 二维前缀和: 绿色点的前缀和就是黄色、红色、灰色和绿色的点权和 怎样计算? s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j]; 绿色部分的前缀和=(红色+灰色)+(黄色+灰色)-...
  • 1.2二维前缀和 2.题目 2.1输入描述: 2.2输出描述: 2.3输入 2.4输出 3.题目理解 3.1思路 4.程序 4.1运行结果 1前缀和 1.1一维前缀和 1.2二维前缀和 求D=(A+B+C+D)-(A+B)-(A+C)+A D=a[x2][y2]-a...
  • 【算法分析】 前缀和并不难理解。前缀和有一维和二维之分。 面对许多高维问题,前缀和往往是大家最先想到的降维方法。由于降维,前缀和能够优化问题的时间复杂度。 什么是前缀和?...二维前缀和:一个二...
  • 二维前缀和简单总结

    2020-01-17 22:51:34
    文章目录二维前缀和简单总结什么是二维前缀和有啥用?具体实施步骤1 .预处理二维数组(`假设为map[][]`)2.实践求某个矩形/正方形区域内的数字和学以致用题解如下 二维前缀和简单总结 注:这篇博客的两张图是我从...
  • 二维前缀和是一维前缀和在二维上的体现,要想了解清楚二维前缀和,最好先学习一维前缀和,在逐步深入二维前缀和。因此我们先从一维的开始讲起,另外一个容易忽视的点是,前缀和优化的是查询复杂度,而不是总体的...
  • 一维 二维 前缀和

    2020-02-04 22:18:08
    一维 二维 前缀和 一维: 略 二维: 模板题入口 #include<bits/stdc++.h> using namespace std; const int N=1010; int a[N][N],s[N][N]; int n,m,k; int main(){ cin>>n>>m>>k; for...
  • 【一维前缀和】 给定一个数组A[1,2,……n],则它的前缀和数组为PrefixSum[1..n]。定义为:PrefixSum[i] = A[0]+A[1]+...+A[i-1]; 【例子】 A[5,6,7,8] --> PrefixSum[5,11,18,26] PrefixSum[0] =A[0] ; ...
  • 思考:只要求二维前缀和(淹没为1,没有淹没为0)对于每次询问,只需要O(1)的时间。 //二维前缀和 //把s[0][i]和s[i][0]全部置为0 //s[i-1][j-1]加重复了,必须减去。 s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 36,626
精华内容 14,650
关键字:

二维前缀和