差分算法模板

差分算法模板

  • 一维差分
    • 一维insert函数(构造差分数组和实现区域加数操作)
    • 一维差分模板题
  • 二维差分
    • 二维insert函数(构造差分数组和实现区域加数操作)
    • 二维差分模板题

一维差分

差分主要是计算出某个区域段的数分别加上一个数

先给定一个原数组a:a[1], a[2], a[3], a[n];
然后我们构造一个数组b : b[1] ,b[2] , b[3], b[i];
使得 a[i] = b[1] + b[2 ]+ b[3] +, + b[i]
也就是说,a数组是b数组的前缀和数组,反过来我们把b数组叫做a数组的差分数组。换句话说,每一个a[i]都是b数组中从头开始的一段区间和。

差分数组公式: b[i] = a[i] - a[i - 1]

一维insert函数(构造差分数组和实现区域加数操作)

我们先来讲讲用insert函数实现区域加数操作

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

比如首先让差分b数组中的 b[l] + c ,a数组变成 a[l] + c ,a[l+1] + c, a[n] + c
理解了这一点,就可以推出以下的公式
在这里插入图片描述

b[l] + c,效果使得a数组中 a[l]及以后的数都加上了c(红色部分),但我们只要求l到r区间加上c, 因此还需要执行 b[r+1] - c,让a数组中a[r+1]及往后的区间再减去c(绿色部分),这样对于a[r] 以后区间的数相当于没有发生改变。

得出一维差分结论:给a数组中的[ l, r]区间中的每一个数都加上c,
只需对差分数组b做 b[l] + = c, b[r+1] - = c

同时,通过这个insert函数,我们也可以用来构造差分数组

void insert(int l, int r, int v)
{
    b[l] += v;
    b[r + 1] -=v;
}
for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
        insert(i, i, a[i]);  //差分数组默认初始化为
    }  

根据差分数组公式:b[1] = a[1] b[2] = a[2] - a[1],
可以试着 模拟几次数据
i = 1时, 在[1, 1] 这个区间 加上a[i]—> b[1] = a[1] b[2] - = a[1]
i = 2时候, b[2] += a[2] --> 也就相当于 b[2] = a[2] - a[1]
(前面i = 1的时候,减去过a[1],后面i = 2时,加上a[2])
这种做法就比较巧妙

一维差分模板题

在这里插入图片描述
在这里插入图片描述

#include<iostream>
#include<cstdio>

using namespace std;

//一维差分模板
//差分的作用:就是用来计算某个区间断,加上某个数
//注意:差分和前缀和的数组下标都是从1开始的

const int N = 1e5 + 10;
int a[N];  //原数组
int b[N];  //差分数组
//差分数组的前缀和就是原数组

//差分数组的求法:
/*
    差分数组默认初始化为0,但是要实现,在某个区间端加上某一个数
    就要先有原来数组的数据,然后再进行加数的操作
    这里统一,可以使用insert(int l, int r, int v)函数来进行操作
    
    l代表左端点,r代表端点,v代表加的数的大小
    函数的作用:在区间[l, r]这个区间中,加上v这个数
    
    赋给原来数组的数据可以用  insert(i, i, a[i]);  

    例如 :b[1] = 0;  在i = 1的时候,在[1, 1]这个区间中插入 a[i]的值
    但是由于插入之后,后面前缀和数组也要发生变化,所以后面也得减去v
    
    b[l]变化 ,b[l]后面的也得变化,[l, r]也加上了v, 所以r + 1后面的,都减去v
*/

//注意:此处要假设  a[n] 是b[n]的前缀和
//即 : a[n] = b[1] + b[2] + b[3]...... + b[n];

void insert(int l, int r, int v)
{
    b[l] += v;
    b[r + 1] -=v;
}

int main()
{
    int n, m;
    cin >> n >> m;
    
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
        insert(i, i, a[i]);  //差分数组默认初始化为
    }  
    
    int l, r, c;
    while(m--)
    {
        cin >> l >> r >> c;
        insert(l, r, c);
    }
    
    //算差分和数组
    for(int i = 1; i <= n; i++)
    {
        b[i] += b[i - 1];    // 这里直接在原数组上进行了前缀和的计算,a[i] = b[i] + a[i - 1];
    }
    
    for(int i = 1; i <= n; i++)
    {

> 这里是引用

        cout << b[i] << " ";
    }
    return 0;
}

这里注意:算出差分数组b[i],并不是结果数组,结果数组是a[i],要对b[i]进行前缀和算出a数组

二维差分

一维变成二维,其他步骤基本没变化,变化的是insert函数

二维insert函数(构造差分数组和实现区域加数操作)

在这里插入图片描述
在这里插入图片描述

这里采用了acwing中一位大佬的题解,讲解的非常好
然后我们就得到了二维差分数组中的差分数组

void insert(int x1, int y1, int x2, int y2, int c)
{
	b[x1][y1] += c;
	b[x1][y2 + 1] -=c;
	b[x2 + 1][y1] -= c
	b[x2 + 1][y2 + 1] += c;
}

同样利用这个insert函数,也能构造出二维的差分数组,思路跟一维的类似,这里就不在详细说了,不懂的再去看看前面一维那部分的讲解。

二维差分模板题

在这里插入图片描述
在这里插入图片描述

#include<iostream>
#include<cstdio>

using namespace std;

const int N = 1010;
int a[N][N],b[N][N];
int n, m, q;


void insert(int x1, int y1, int x2, int y2, int c)
{
    b[x1][y1] +=c;
    b[x2 + 1][y1] -=c;
    b[x1][y2 + 1] -=c;
    b[x2 + 1][y2 + 1] +=c;
}

int main()
{
    
    cin >> n >> m >> q;
    
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            cin >> a[i][j];
            insert(i, j, i, j, a[i][j]); //差分数组初始化
        }
    }
    
    //区间加上某个数
    int x1, y1, x2, y2, c;
    while(q--)
    {
        cin >> x1 >> y1 >> x2 >> y2 >> c;
        insert(x1, y1, x2, y2, c);   
    }
    
    //算出a[n]
    
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            //可以在在b数组本身上进行前缀和加的计算()
            //方式一:
            //b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];
            
            //也可以这样
            //方式二:用原数组进行 a[i][j] = a[i -1][j] + a[i][j - 1] - a[i - 1][j - 1] + b[i][j]
            
            a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + b[i][j];
        } 
    }
    
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            //方式一:
            //cout << b[i][j] << " ";
            
            //方式二:
            cout << a[i][j] << " ";
            
        }
        cout << endl;
    }
    
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【python入门】day28:记录用户登录日志

演示 代码 #-*- coding:utf-8 -*- print(记录用户登录日志----------------------------) import time def show_info():print(输入提示数字,执行相应操作:0退出,1查看登录日志) def write_logininfo(username):#----------记录日志with open(log.txt,a,encodingutf-8)as file…

Tensor Core的一些概念理解

英伟达的GPU产品架构发展如下图&#xff0c;Tensor Core是从2017年的Volta架构开始演变的针对AI模型大量乘加运算的特殊处理单元。本文主要梳理一些关于Tensor Core的一些基础概念知识。 什么是混合精度&#xff1f; 混合精度在底层硬件算子层面&#xff0c;使用半精度&#xf…

阶段十-分布式锁

5.1 节 为什么要使用分布式锁 锁是多线程代码中的概念&#xff0c;只有当多任务访问同一个互斥的共享资源时才需要。如下图&#xff1a; 在我们进行单机应用开发&#xff0c;涉及并发同步的时候&#xff0c;我们往往采用synchronized或者lock的方式来解决多线程间的代码同步问…

【Python】使用pyinstaller打包为Windows平台的xxx.exe方法步骤

pyinstaller 是一个用于将 Python 代码打包成独立可执行文件的工具&#xff0c;它可以将 Python 代码打包成 Windows、Linux、Mac 等平台的可执行文件&#xff0c;方便用户在不同环境中运行。 pyinstaller用法&#xff1a; 1.安装pyinstaller库&#xff0c;这里以PyCharm环境为…

第六站:C++面向对象

面向对象的第一概念:类 类的构成: “类”&#xff0c;是一种特殊的“数据类型”&#xff0c;不是一个具体的数据。 类的设计: 创建一个类: class Human { public://公有的,对外的void eat();//方法,成员函数void sleep();void play();void work();string getName();//获取对内…

AI大模型学习笔记二

文章目录 一、Prompt Engineering1&#xff09;环境准备 二、LangChain&#xff08;一个框架名字&#xff09;三、Fine-tuning&#xff08;微调&#xff09; 一、Prompt Engineering 1&#xff09;环境准备 ①安装OpenAI库 pip install --upgrade openai附加 安装来源 pyth…

Altium Desigenr 孔 规则修改2

1、过孔修改 在这里插入图片描述 2、物理孔

细说JavaScript表达式和运算符号详解

除了简单的表达式还有复杂的表达式&#xff0c;它是由简单表达式构成的&#xff0c;将简单表达式组合成复杂表达式最常见的方法就是使用运算符 一、表达式 表达式分为简单表达式和复杂表达式&#xff0c;但最后的结果均是返回一个值 1、简单表达式 简单表达式又称为原始表达式…

MongoDB - 索引底层原理和使用,聚合的使用(案例 + 演示)

目录 一、MongoDB 索引 1.1、说明 1.2、原理 1.3、操作 1.3.1、创建索引 1.3.2、查看集合索引列表 1.3.3、查看集合索引大小 1.3.4、删除集合所有索引 1.3.5、删除集合指定索引 1.3.6、创建复合索引 1.4、聚合 a&#xff09; 统计每个作者写的文章数 b&#xff09…

没有自动化测试项目经验,3个项目帮你走入软测职场!

学习自动化测试最难的是没有合适的项目练习。测试本身既要讲究科学&#xff0c;又有艺术成分&#xff0c;单单学几个 API 的调用很难应付工作中具体的问题。 你得知道什么场景下需要添加显性等待&#xff0c;什么时候元素定位需要写得更加优雅&#xff0c;为什么需要断言这个元…

如何用MetaGPT帮你写一个贪吃蛇的小游戏项目

如何用MetaGPT帮你写一个贪吃蛇的小游戏项目 MetaGPT是基于大型语言模型(LLMs)的多智能体写作框架&#xff0c;目前在Github开源&#xff0c;其Start数量也是比较高的&#xff0c;是一款非常不错的开源框架。 下面将带你进入MetaGPT的大门&#xff0c;开启MetaGPT的体验之旅。…

机器人行业概况(2)

上篇已经介绍过关于机器人的定义以及分类&#xff0c;下面来看看机器人产业市场规模。 二、国内机器人产业市场规模 中国机器人产业在国家智能制造相关政策的引导下蓬勃发展。在新冠肺炎疫情防控期间&#xff0c;消毒、配送、测温、巡检等各类机器人的“火线上岗”&#xff0…

Electron中 主进程(Main Process)与 渲染进程 (Renderer Process) 通信的方式

1. 渲染进程向主进程通信 修改 html 文件内容 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><!-- 解决控制…

C# 基础入门

第二章 C# 语法基础 2-1 C# 中的关键字 关键字&#xff0c;是一些被C#规定了用途的重要单词。 在Visual Studio的开发环境中&#xff0c;关键字被标识为蓝色&#xff0c;下图代码中&#xff0c;用红方框圈出的单词就是关键字。 关键字 class &#xff0c;这个关键字的用途是…

【GitHub项目推荐--谷歌大神又一开源代码调试神器】【转载】

如果调试是 Debug 的必经之路&#xff0c;那么编程应该将它考虑在内。今天我就和大家分享一个代码调试神器 - Cyberbrain。 Cyberbrain是一个免费开源的 Python 代码调试解决方案&#xff0c;它可视化程序执行以及每个变量的变化方式&#xff0c;让程序员免受调试之苦。主要具有…

【Docker】centos中及自定义镜像,并且上传阿里云仓库可提供使用

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是平顶山大师&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《【Docker】centos中及自定义镜像&#xff0c;…

零零鸡生态养殖农场“出圈”,有“智”更有“质”,助力本土品牌高质量发展

什么是生态农场&#xff1f;不同于常规农场&#xff0c;它对农业生产经营单元的各个关键环节有着极为严格的要求&#xff0c;强调整体、协调、循环、再生、多样&#xff0c;产品质量自然更好&#xff0c;附加值也更高&#xff0c;更能满足日趋多样化的巨大市场。零零鸡生态农场…

机器学习---xgboost算法

1. xgboost算法原理 XGBoost&#xff08;Extreme Gradient Boosting&#xff09;全名叫极端梯度提升树&#xff0c;XGBoost是集成学习方法的王 牌&#xff0c;在Kaggle数据挖掘比赛中&#xff0c;大部分获胜者用了XGBoost。 XGBoost在绝大多数的回归和分类 问题上表现的十分…

蓝桥杯准备

书籍获取&#xff1a;Z-Library – 世界上最大的电子图书馆。自由访问知识和文化。 (zlibrary-east.se) 书评&#xff1a;(豆瓣) (douban.com) 一、观千曲而后晓声 别人常说蓝桥杯拿奖很简单&#xff0c;但是拿奖是一回事&#xff0c;拿什么奖又是一回事。况且&#xff0c;如果…

用通俗易懂的方式讲解:图解 Transformer 架构

文章目录 用通俗易懂方式讲解系列1.导语2.正文开始现在我们开始“编码”从宏观视角看自注意力机制从微观视角看自注意力机制通过矩阵运算实现自注意力机制残差模块最终的线性变换和Softmax层训练部分总结损失函数再进一步 用通俗易懂方式讲解系列 用通俗易懂的方式讲解&#x…