【算法/学习】前缀和差分

news2024/11/15 15:28:33

前缀和&&差分目录

1. 前缀和的概念及作用

🌈概念

🌈用途

🌙一维前缀和

🌙二维前缀和

2. 差分的概念及用途

🌈概念:

🌈用途

🌙一维差分

🌙二维差分


1. 前缀和的概念及作用

🌈概念

前缀和:

🎈对于一个给定的数列a,他的前缀和数中 s 中 s[ i ] 表示从第一个元素到第 i 个元素的总和。即s[ i ] = s[ i - 1 ] + a[ i ];

比如: s[ 1 ] = s[ 0 ] + a[ 1 ]。   

注意:在使用前缀和和差分的时候,一般下标 0  不参与的运算,统一的将下表设置为从1开始,具体是要考虑到我们的边界问题,也就是S[1]的求法问题,为了保证我们循环的统一性,我们要将S[0]设置为0,所以我们索性就将下标从1开始设置起,这样也有利于我们后面的初始化。

🌈用途

可以用于一维前缀和和二维前缀和。

模板如下:

🌙一维前缀和

核心代码如下:

s[i] = s[i-1] + a[i]
s[i] = a[1] + a[2] + ... a[i]
a[l] + ... + a[r] = s[r] - s[l - 1]

🧩例题如下:

 题目练习: AcWing 795. 前缀和

思路:

首先做一个预处理,定义一个s数组,让s[ i ]代表 a 数组前 i 个数的和。

然后运用求一维前缀和运算的公式 s[i] = s[i-1] + a[i] 

再进行查询操作:即s[ r ] - s[ l - 1] ,这样使得求 [ l, r ]的和的时间复杂度变为 O (1).

注意:求 [ l, r ]的和是s[ r ] - s[ l - 1],之所以要 l - 1是因为,a[ l ] 也包括在内

因为a[l] + ... + a[r] = s[r] - s[l - 1]

AC代码如下:

#include <iostream>
using namespace std;

const int N = 1e5+10;
int a[N], s[N];

int main(){
    int n, m, x;
    cin>>n>>m;
    for(int i = 1; i <= n; i++) cin>>a[i];
    for(int i = 1; i <= n; i++) s[i] = a[i] + s[i - 1];
    int l, r;
    while(m--){
        cin>>l>>r;
        cout<<s[r] - s[l - 1]<<endl;
    }
    return 0;
}


🌙二维前缀和

和一维前缀和的原理类似,只不过二维前缀和求的是一个矩阵中所有元素的和。

如下图:


因此通过上面的图我们就可以更好理解下图来推导公式了:

s[ i ][ j ] 即为框内所有数的和:s[ i ][ j ]=s[ i ][ j - 1 ]+s[ i - 1 ][ j ] - s[ i - 1 ][ j - 1 ]+a[ i ][ j ];

而(x1, y1) 到 (x2, y2)的矩阵大小为s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]

核心代码:

s[x][y]=s[x][y-1]+s[x-1][y]-s[x-1][y-1]+a[x][y];
s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]

🧩例题如下:

  题目练习: AcWing 796. 子矩阵的和

思路:

先做一个预处理,定义一个s矩阵,s[ i ][ j ]代表 a 矩阵 从(0,0)到(i,j)的矩阵和。

然后运用求一维前缀和运算的公式 s[i] = s[i-1] + a[i] 

再进行查询操作:即s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]。

这样使得求 (x1, y1) 到 (x2, y2)的矩阵大小的和的时间复杂度变为 O (1).

AC代码如下:

#include <iostream>
using namespace std;

const int N = 1005;
int a[N][N], s[N][N];

int main(){
	int n, m, q;
	cin >> n >> m >> q;
	//第一步:输入矩阵的值
	for (int i = 1; i <= n; i++){
		for (int j = 1; j <= m; j++){
			cin >> a[i][j];
		}
	}
	//第二步:求矩阵前缀和
	for (int i = 1; i <= n; i++){
		for (int j = 1; j <= m; j++) {
			s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
		}
	}
	//第三步:查找(x1,y1)到(x2,y2)的矩阵大小
	while (q--)
	{
		int x1, x2, y1, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		printf("%d\n", s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1]);
	}

	return 0;
}


2. 差分的概念及用途

🌈概念:

差分:

🎈 类似于数学中的求导和积分,差分可以看成前缀和的逆运算

对于一个给定的数列a,其中a[1],a[2]…a[n]作为前缀和。它的差分数组中 b 中 b[ i ] 表示从第 i - 1个元素到第 i 个元素的差值。即b[ i ] = a[ i ] - s[ i - 1 ];

一维差分数组的构造也很简单,即a[1] = b[1], b[2] = a[2] - a[1], b[n] = a[n] - a[n-1];

注意:刚开始时可以初始化数组a,b全部为0,输入a数组后;在构造时,只需要将b[1]看做在[1, 1]区间上加上a[1]; b[2] 看作在[2, 2]区间上加上a[2];

🌈用途

🌙一维差分

      差分数组的好处是可以简化运算,例如想要给一个区间 [l,r] 上的数组加一个常数c原始的方法是依次加上c,这样的时间复杂度是O(n)的。但是如果采用差分数组的话,可以大大降低时间复杂度到O(1)。

       因此只需要将b[l] = b[l] + c 即可,这样l之后的数字会依次加上常数c,而在 b[r]处,将b[r+1] = b[r+1] - c ,这样r之后的数组又会恢复原值,仅需要处理这两个边界的差分数组即可。时间复杂度大大降低。

核心代码如下:

b[i]=a[i]-a[i-1];
a[i] = b[i] + a[i - 1];

🧩例题如下:

题目练习: AcWing 797. 差分

思路:

首先做一个预处理,定义一个b数组,让b[ i ]代表a[ i ] - a[ i -1 ].

因此只需要将b[l] = b[l] + c 即可,这样l之后的数字会依次加上常数c,而在 b[r]处,将b[r+1] = b[r+1] - c ,这样r之后的数组又会恢复原值,仅需要处理这两个边界的差分数组即可。

AC代码如下:

#include <iostream>
using namespace std;

const int N = 1e5 + 5;
int b[N], a[N];

int main()
{
	int n, m;
	cin>>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;
	    cin>>l>>r>>c;
	    b[l]+=c;
	    b[r+1]-=c;
	}
	
	for (int i = 1; i <= n; i++){
		a[i] = b[i] + a[i - 1];
		printf("%d ", a[i]);
	}
	return 0;
}


🌙二维差分

如果扩展到二维,我们需要让二维数组被选中的子矩阵中的每个元素的值加上c,是否也可以达到O(1)的时间复杂度。答案是可以的,考虑二维差分

a[][]数组是b[][]数组的前缀和数组,那么b[][]a[][]的差分数组

原数组: a[i][j]

我们去构造差分数组: b[i][j]

使得a数组中a[i][j]b数组左上角(1,1)到右下角(i,j)所包围矩形元素的和。

如何构造b数组呢?

其实关于差分数组,我们并不用考虑其构造方法,因为我们使用差分操作在对原数组进行修改的过程中,实际上就可以构造出差分数组。

同一维差分,我们构造二维差分数组目的是为了 让原二维数组a中所选中子矩阵中的每一个元素加上c的操作,可以由O(n*n)的时间复杂度优化成O(1)

已知原数组a中被选中的子矩阵为 以(x1,y1)为左上角,以(x2,y2)为右下角所围成的矩形区域;

始终要记得,a数组是b数组的前缀和数组,比如对b数组的b[i][j]的修改,会影响到a数组中从a[i][j]及往后的每一个数。

假定我们已经构造好了b数组,类比一维差分,我们执行以下操作
来使被选中的子矩阵中的每个元素的值加上c

b[x1][y1] + = c ;

b[x1,][y2+1] - = c;

b[x2+1][y1] - = c;

b[x2+1][y2+1] + = c;

每次对b数组执行以上操作,等价于:

b[x1][y1] += c ; 对应图1 ,让整个a数组中蓝色矩形面积的元素都加上了c。
b[x1,][y2 + 1] -= c ; 对应图2 ,让整个a数组中绿色矩形面积的元素再减去c,使其内元素不发生改变。
b[x2 + 1][y1] -= c ; 对应图3 ,让整个a数组中紫色矩形面积的元素再减去c,使其内元素不发生改变。
b[x2 + 1][y2 + 1] += c; 对应图4,让整个a数组中红色矩形面积的元素再加上c,红色内的相当于被减了两次,再加上一次c,才能使其恢复。

核心代码如下:

b[i][j] = a[i][j] − a[i − 1][j] − a[i][j − 1] + a[i −1 ][j − 1]
b[x1][y1] += c;
b[x2 + 1][y1] -= c;
b[x1][y2 + 1] -= c;
b[x2 + 1][y2 + 1] += c;

题目练习: AcWing 798. 差分矩阵

AC代码如下:

#include <iostream>
using namespace std;

const int N = 1005;
int a[N][N], b[N][N];

int main(){
	int n, m, q;
	cin >> n >> m >> q;
	for (int i = 1; i <= n; i++){
		for (int j = 1; j <= m; j++) {
			cin >> a[i][j];
			b[i][j] = a[i][j] - a[i - 1][j] - a[i][j - 1] + a[i - 1][j - 1];
		}
	}
	while (q--){
		int x1, x2, y1, y2, c;
		cin >> x1 >> y1 >> x2 >> y2 >> c;
		b[x1][y1] += c, b[x2 + 1][y2 + 1] += c;
		b[x1][y2 + 1] -= c, b[x2 + 1][y1] -= c;
	}

	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + b[i][j];
			cout << a[i][j] << " ";
		}
		cout << endl;
	}
	
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1943145.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

sap 权限控制例子

文章目录 1 T-code2 Method3 Summary 1 T-code We use t-code is ‘su21’ and ‘PFCG’ . Creat Authorization objects . Create role 2 Method DATA: zbz(1).CLEAR:zbz.SELECT SINGLE COUNT(*) FROM agr_users WHERE uname sy-uname AND agr_name ZMM_PRICE001.&q…

redis全局唯一ID生成策略、countDownLatch、Lambda表达式总结

redis全局唯一ID生成策略 一、有哪些生成全局唯一ID的策略二、使用Redis自增1. 分析2. RedisIdWorker配置类3 单元测试注解分析&#xff08;难点较多&#xff09;3.1 countDownLatch前言3.2 常用方法 一、有哪些生成全局唯一ID的策略 二、使用Redis自增 1. 分析 2. RedisIdWor…

《数据结构1800题》基础回合总结——第1章 绪论

前言&#xff1a;《数据结构1800》这本书相信大家或多或少都有所耳闻&#xff0c;收录了诸多不同档次学校的考研真题&#xff0c;因为和汤老师的1800撞名所以备受调侃。这1800道题目里面有选择有填空&#xff0c;也有简答和一些编程题&#xff0c;总的来说质量良莠不齐——亦或…

Transformer之Swin-Transformer结构解读

写在最前面之如何只用nn.Linear实现nn.Conv2d的功能 很多人说&#xff0c;Swin-Transformer就是另一种Convolution&#xff0c;但是解释得真就是一坨shit&#xff0c;这里我郑重解释一下&#xff0c;这是为什么&#xff1f; 首先&#xff0c;Convolution是什么&#xff1f; Co…

GaussianPro使用笔记

1. 介绍 GaussianPro: 3D Gaussian Splatting with Progressive Propagation 3D高斯分布(3DGS)最近以其高保真度和效率彻底改变了神经渲染领域。然而&#xff0c;3DGS在很大程度上依赖于运动结构&#xff08;SfM&#xff09;技术生成的初始化点云。当处理不可避免地包含无纹理…

语音识别 语音识别项目相关笔记内容

语音识别 语音识别项目相关笔记内容 语音识别应用范畴语音识别框架语音基本操作使用scipy.io.wavfile读取wav音频文件获取采样率、长度、通道数使用numpy读取pcm格式音频文件读取wav音频文件,并绘制图像读取双声道的wav音频文件,分别绘制不同声道的波形图读取一个采样率为16k…

拍立淘API返回值:图像搜索技术的商品信息获取指南

拍立淘API是基于图像搜索技术的商品信息获取工具&#xff0c;广泛应用于阿里巴巴旗下的电商平台如淘宝、天猫等。这一API通过用户上传的商品图片&#xff0c;利用深度学习、计算机视觉等先进技术自动识别图片中的商品信息&#xff0c;并返回与之相关的搜索结果。以下是对拍立淘…

go语言Gin框架的学习路线(八)

目录 GORM Model定义 使用 Model 结构体的自定义数据模型 理解并记忆 GORM 的 Model 结构体可以通过以下几个步骤和技巧&#xff1a; 1. 理解基本概念 2. 熟悉基本字段 3. 记忆技巧 4. 使用场景 结构体标记 支持的结构体标记&#xff08;Struct tags&#xff09; 关联…

浏览器渲染揭秘:从加载到显示的全过程;浏览器工作原理与详细流程

目录 浏览器工作原理与流程 一、渲染开始时间点 二、渲染主线程的渲染流程 2.1、渲染流程总览 2.2、渲染具体步骤 ①解析html-Parse HTML ②样式计算-Recalculate Style ③布局-Layout ④分层-Layer 相关拓展 ⑤绘制-Paint ⑥分块-Tiling ⑦光栅化-Raster ⑧画-D…

四川赤橙宏海商务信息咨询有限公司引领抖音电商新趋势

随着互联网的飞速发展&#xff0c;电子商务已成为企业竞争的新高地。在众多电商平台中&#xff0c;抖音以其独特的短视频直播形式&#xff0c;吸引了亿万用户的目光&#xff0c;成为电商领域的新宠。在这样的背景下&#xff0c;四川赤橙宏海商务信息咨询有限公司凭借其专业的电…

新零售电商:订单管理系统设计

传统电商依托于线上流量产生消费者&#xff0c;新零售则是通过网上商城、小程序以及其他应用程序相结合形成网店&#xff0c;同时与线下实体门店和现代物流进行深度整合&#xff0c;最终形成了新的销售模式。 订单管理系统上下游对接系统繁杂&#xff0c;包括&#xff1a;商品中…

【Java语法基础】1、变量、运算符、输入输出

1.变量、运算符、输入输出 跟C一样&#xff0c;先把必须写的框架写出来&#xff1a; package org.example; public class Main{public static void main(String[] args){//在里面写实际的代码} }变量 必须先定义&#xff0c;才能使用。与C、C差不多。 没有赋初值的变量无法…

如何实现Web服务只允许特定客户端访问

如何实现Web服务只允许特定客户端访问 需求来源 为了满足B/S系统给客户演示的需要&#xff0c;需要部署一套系统允许公网能够访问&#xff0c;便于业务人员到客户哪里进行系统演示&#xff0c;但是目前网络安全非常重要&#xff0c;希望能防止暴力破解或者端口扫描等黑客攻击…

全网最实用--神经网络各个组件以及效率指标 (含代码助理解,粘贴即用)

文章目录 一、神经网络相关组件0.前奏1.全连接层&#xff08;Fully Connected Layer, FC&#xff09;/密集层&#xff08;Dense Layer&#xff09;:2.卷积层&#xff08;Convolutional Layer, Conv&#xff09;:a.一维卷积b.二维卷积c.分组卷积 3.池化层&#xff08;Pooling La…

汇编语言例题分析

以下数据段定义了如下数据&#xff0c;对应内存图请填空&#xff0c;写出每个内存字节中的2位16进制数&#xff08;注意写准确&#xff0c;2位16进制数&#xff0c;末尾不带h&#xff09;。 Data1 segment x db 1,2,3 y db “ABa” z dw 1,2 Data1 ends 物理地址从0000开始&…

C语言指针超详解——最终篇二

C语言指针系列文章目录 入门篇 强化篇 进阶篇 最终篇一 最终篇二 文章目录 C语言指针系列文章目录1. sizeof 与 strlen1.1 字符数组1.2 二维数组 2. 指针运算笔试题解析 以上接指针最终篇一 1. sizeof 与 strlen 1.1 字符数组 代码三&#xff1a; #include<stdio.h>…

『 Linux 』System V共享内存

文章目录 System V IPCSystem V 共享内存的直接原理System V共享内存的创建挂接共享内存取消挂接共享内存释放共享内存利用System V共享内存进行进程间通信共享内存的特性共享内存的属性通过命名管道为共享内存添加同步互斥机制 System V IPC System v 是一种操作系统和相关技术…

不懂这些,面试都不敢说自己熟悉Redis

点赞再看&#xff0c;Java进阶一大半 下面这位就是Redis的创始人&#xff0c;他叫antirez&#xff0c;让我们Java开发者又要多学一门Redis的始作俑者。 我们肯定很难想象Redis创始人竟然学的是是建筑专业&#xff0c;而当年antirez是为了帮网站管理员监控访问者的实时行为才开发…

22集 如何minimax密钥和groupid-《MCU嵌入式AI开发笔记》

22集 如何获取minimax密钥和groupid-《MCU嵌入式AI开发笔记》 minimax密钥获取 https://www.minimaxi.com/platform 进入minimax网站&#xff0c;注册登录后&#xff0c;进入“账户管理”&#xff0c; 然后再点击“接口密钥”&#xff0c;然后再点击“创建新的密钥”。 之…

linux系统安装python3和pip

一、安装python 1、安装依赖环境 yum install gcc -y yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel yum install zlib zlib-devel openssl -y yum install openssl…