第四章:前缀和、差分(数列)

news2025/7/10 9:27:02

前缀和差分

  • 一、前缀和
    • 1、 什么是前缀和
    • 2、 前缀和的作用
    • 3、 前缀和的例题和模板
      • (1)一维数组的前缀和
        • C++版
        • C版
      • (2)二维数组的前缀和
        • a.思路:
        • b.题目和模板:
          • C++版
          • C版
  • 二、差分
    • 1、什么是差分?
    • 2、差分有什么作用?
    • 3、一维差分:
      • (1)思路:
      • (2)题目和模板
        • C++版
        • C版
      • (3)优化
        • C++版
        • C版
    • 4、二维差分:
      • (1)思路:
      • (2)题目和模板
        • C++版
        • C版

一、前缀和

1、 什么是前缀和

在解释什么是前缀和之前,我们先回顾一下高中学过的数列:在这里插入图片描述
我们这里所说的前缀和其实就是我们在高中学的数列中的Sn(前n项和),只是我们这里需要将S1 , S2 , S3 , S4 …… Sn当作一个新的数组。

为了这个式子的高度统一性,我们的S0和a0都是不存储数据的,将其设置为0,这样当n等于1的时候,也满足上面的式子。

2、 前缀和的作用

我们看下面这段数学推导:
请添加图片描述

如果我们想特定几项an的和,那么我们就需要取遍历数组an,然后才能求出最终的和,我们发现这种情况的时间复杂度是O(N)
但是我们使用前缀和Sn去计算的话,我们发现只需要一个简单是式子,其时间复杂度是O(1)。因此,我们便能够发掘出前缀和的作用:更快地求解数列的和
而这除了是利用了数学中的数列知识,更是一种用空间换时间的重要思想。

3、 前缀和的例题和模板

(1)一维数组的前缀和

其实前缀和就是一个公式,因此其模板是很简单的。
在这里插入图片描述

C++版

#include<iostream>
using namespace std;
const int N=1e6+10;
int arr[N];
int S[N];
int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&arr[i]);
    for(int i=1;i<=n;i++)S[i]=S[i-1]+arr[i];
    
    while(m--)
    {
        int l,r;
        scanf("%d %d",&l,&r);
        printf("%d\n",S[r]-S[l-1]);
    }
    return 0;    
}

C版

#include<stdio.h>
const int N=1e6+10;

int main()
{
	int arr[N];
	int S[N];
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&arr[i]);
    for(int i=1;i<=n;i++)S[i]=S[i-1]+arr[i];
    
    while(m--)
    {
        int l,r;
        scanf("%d %d",&l,&r);
        printf("%d\n",S[r]-S[l-1]);
    }
    return 0;    
}

(2)二维数组的前缀和

a.思路:

在了解思路之前,我们应该先明白,什么是二维数组的前缀和,即二维数组的前n项和所指的是哪几项的和?
请添加图片描述
如图中所示,二维数组的前缀和就是图中方形所覆盖的an的和,包括边界!!!!

那么我们如何利用递推公式写出前缀和呢?
如下图所示:
在这里插入图片描述

那么在理解了二维数组的前缀和的概念后,我们看下面这个问题:
我们如何计算这个紫色方形范围内的an的面积呢?
请添加图片描述

图中所示的求法类似于我们高中所学的概率内容中的容斥原理
即我们先减去两部分,然后再加上重复减去的部分。但是我们要时刻注意边界问题,图中的式子之所以减一,就是因为紫色方形的边界也要算到前缀和中。

b.题目和模板:

题目:
在这里插入图片描述

C++版
#include<iostream>
using namespace std;
const int N=1010;
int a[N][N];
int S[N][N];
int main()
{
    int n,m,q;
    scanf("%d %d %d",&n,&m,&q);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&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];
        }
    }
    while(q--)
    {
        int x1,y1,x2,y2;
        scanf("%d %d %d %d",&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;
}
C版
#include<stdio.h>
const int N=1010;

int main()
{
	int a[N][N];
	int S[N][N];
    int n,m,q;
    scanf("%d %d %d",&n,&m,&q);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&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];
        }
    }
    while(q--)
    {
        int x1,y1,x2,y2;
        scanf("%d %d %d %d",&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;
}

二、差分

1、什么是差分?

我们知道前缀和是一个数组中的前N项和,其实差分就是原数组an。

因此我们就能够发现,一个数列当中,an是差分,an的前n项和sn是前缀和。

2、差分有什么作用?

我们通过前缀和可以在时间复杂度为O(1)的情况下,计算出几项的和。那么差分则可以在时间复杂度为O(1)的情况下,给数列中的某几项都加上常数C。假设我们不适用差分的话,我们需要遍历原数组然后逐一加上常数C,此时的时间复杂度就是O(N)

由此我们就能够总结出差分的作用:在时间复杂度是O(1)的前提下,将数组中的某几项加上特定的常数C。那么怎么加呢?我们看下面的内容。

3、一维差分:

(1)思路:

我们应该如何实现上面所说的差分的作用呢?我们看下面这张图片:
请添加图片描述
由上图可知:
我们只需要将bn中的第L项加上C,第r+1项减去C即可。这样我们在通过bn算an的时候,就能够在L到r的闭区间上的an都加上常数C。但此时的时间复杂度仅仅是O(1)

(2)题目和模板

在这里插入图片描述

C++版

#include<iostream>
using namespace std;
const int N=100001;
int a[N];
int b[N];
int main()
{
	//读取数据
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",a+i);
    //构造b数组:使得ai是bi的前缀和
    for(int i=1;i<=n;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;
    }
    //利用b数组打印a数组
    for(int i=1;i<=n;i++)printf("%d ",b[i]+=b[i-1]);
    return 0;
}

C版

#include<stdio.h>

const int N=100001;

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

(3)优化

这里我们在介绍一种不用特意构造b数组的方法。
我们假设an数列初始化全为0,那么此时我们输入a1的时候,就相当于在[1,1]上插入一个a1。同理,an就相当于在[n,n]上插入一个an。我们就能够采用这种方式来初始化bn数组,如果不理解的话,大家可以自己写几个例子。

C++版

#include<iostream>
using namespace std;
const int N=100010;
int a[N],b[N];

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

int main()
{
    int n,m;
    cin>>n>>m;
    
    for(int i=1;i<=n;i++)
    {   
        scanf("%d",a+i);
        insert(i,i,a[i]);
    }
    while(m--)
    {
        int l,r,c;
        scanf("%d %d %d",&l,&r,&c);
        insert(l,r,c);
    }
    for(int i=1;i<=n;i++)printf("%d ",b[i]+=b[i-1]);
    return 0;
}

C版

#include<stdio.h>
int a[100010],b[100010];
void insert(int l,int r,int c)
{
    b[l]+=c;
    b[r+1]-=c;
}

int main()
{
   
    int n,m;
    scanf("%d %d",&n,&m);
    
    for(int i=1;i<=n;i++)
    {   
        scanf("%d",a+i);
        insert(i,i,a[i]);
    }
    while(m--)
    {
        int l,r,c;
        scanf("%d %d %d",&l,&r,&c);
        insert(l,r,c);
    }
    for(int i=1;i<=n;i++)printf("%d ",b[i]+=b[i-1]);
    return 0;
}

4、二维差分:

(1)思路:

我们先上下面的图示:
请添加图片描述
先解决第一个问题,为什么b[i,j]+c后是右下角的数列元素加c呢?其实很好理解,因为an是bn的前n项和,因此只有右下角的an计算时,才会包括该点。因此,b[i,j]+c后影响的是右下角。
然后我们就可以根据上图中公式使得黄色区域的an都加上C。

(2)题目和模板

在这里插入图片描述

C++版

#include<iostream>
using namespace std;

const int N=1010;
int a[N][N];
int b[N][N];

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()
{   
    int n,m,q;
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&a[i][j]);
            insert(i,j,i,j,a[i][j]);
        }
    }
    while(q--)
    {
        int x1,y1,x2,y2,c;
        cin>>x1>>y1>>x2>>y2>>c;
        insert(x1,y1,x2,y2,c);
    }
    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]+b[i][j];
            printf("%d ",a[i][j]);
        }
        cout<<endl;
    }
    return 0;
}

C版

#include<stdio.h>

int a[1010][1010];
int b[1010][1010];

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()
{   
    int n,m,q;
    scanf("%d %d %d",&n,&m,&q);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&a[i][j]);
            insert(i,j,i,j,a[i][j]);
        }
    }
    while(q--)
    {
        int x1,y1,x2,y2,c;
        scanf("%d %d %d %d %d",&x1,&y1,&x2,&y2,&c);
        insert(x1,y1,x2,y2,c);
    }
    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]+b[i][j];
            printf("%d ",a[i][j]);
        }
        printf("\n");
    }
    return 0;
}

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

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

相关文章

FFplay文档解读-43-视频过滤器十八

29.170 telecine 将电视电影处理应用于视频。 此过滤器接受以下选项&#xff1a; first_field选项解释top, ttop field firstbottom, b底部字段优先默认值为top pattern一串数字&#xff0c;表示希望应用的下拉模式。 默认值为23。 Some typical patterns:NTSC output (30i…

传统纸业如何实现数字化,S2B2C系统网站赋能渠道提升供应链管理效率

一千多年前&#xff0c;我们老祖宗发明了造纸术&#xff0c;纸张成为方便、廉价的信息载体&#xff0c;由此影响了中国乃至世界文明的进程。如今&#xff0c;随着信息技术的普及&#xff0c;纸张作为信息载体的功能日益弱化&#xff0c;但作为一种环保材料将会更广泛地融入我们…

通过宠物商店理解java面向对象

前言&#xff1a;本篇博客&#xff0c;适合刚刚学完java基础语法的但是&#xff0c;对于面向对象&#xff0c;理解不够深刻的读者&#xff0c;本文通过经典的宠物商店&#xff0c;来让读者深刻的理解&#xff0c;面向对象&#xff0c;IS-A&#xff0c;HAS-A法则。本文不仅仅是简…

Spring更简单保存和获取bean对象的方法(注解)

Spring更简单保存和获取bean对象的方法前置准备将bean对象更为简单地保存到Spring容器中&#xff08;使用注解&#xff09;【使用类注解】 (是写在类前的)为什么要这么多类注解&#xff1f;类注解之间的关系使用类注解 Bean 命名规则使用方法注解&#xff08;Bean&#xff09;不…

[MySQL]数据库的约束与表的设计

专栏简介 :MySql数据库从入门到进阶. 题目来源:leetcode,牛客,剑指offer. 创作目标:记录学习MySql学习历程 希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长. 学历代表过去,能力代表现在,学习能力代表未来! 文章目录 1.数据库约束 1.1 约束类型 1.2 null 约束 1.…

Redis面试题

目录 面试题&#xff1a;谈谈你对Redis的理解&#xff1f; 面试题&#xff1a;Redis的基本数据类型 Redis的基本数据类型以及它们的应用场景&#xff1a; 面试题&#xff1a;redis内存淘汰机制 面试题&#xff1a;Redis持久化机制 RDB AOF 面试题&#xff1a;Redis写时复…

相似度系列-3:传统方法ROUGE ROUGE: A Package for Automatic Evaluation of Summaries

文章目录ROUGE: A Package for Automatic Evaluation of Summariesintroduction基础模型Rouge-NRouge_NmultiROUGE-L: Longest Common Subs equence1**Sentence-level LCS**2**Summary-Level LCS**ROUGE-W: Weighted Longest Common SubsequenceROUGE-S: Skip-Bigram Co-Occurr…

Python小总结

Python小总结一、open&#xff08;一&#xff09;open的定义&#xff1a;open是Python的内置函数&#xff0c;一般用于本地文件的读写操作。&#xff08;二&#xff09;open例子&#xff1a;二、with open&#xff08;一&#xff09;用途&#xff1a;with open是Python用来打开…

04 数学软件与建模---最优化模型

一、优化模型的数学描述 二、优化模型的分类 1.根据是否存在约束条件 有约束问题和无约束问题。 2.根据设计变量的性质 静态问题和动态问题。 3.根据目标函数和约束条件表达式的性质 线性规划&#xff0c;非线性规划&#xff0c;二…

PiL测试实战(上)| 模型生成代码的单元级PiL测试

前言 对于嵌入式代码&#xff0c;为了测试软件能否在目标芯片上实现预期的功能&#xff0c;通常需要进行PiL测试&#xff08;Processor-in-the-Loop-Testing&#xff09;。 目前市面上较为常见的嵌入式软件调试工具有PLS UDE和LAUTERBACH Trace32等。UDE和Trace32可以很好的完…

通俗易懂话GC-C#的内存管理

昨天和一个朋友聊到图像处理软件内存占用多的问题&#xff0c;然后很自然聊到了GC&#xff0c;回想起以往很初学者都问到类似的问题&#xff1a; 1、C#自己就会垃圾回收&#xff0c;为什么我还要关心垃圾回收&#xff1f; 2、GC可以回收垃圾&#xff0c;但回收的时候又会让线…

js深浅拷贝:保证赋值后改变第二个变量的值,不影响第一个变量的值

对于基本数据来说&#xff0c;将一个变量赋值给另一个变量&#xff0c;第二个变量值改变了&#xff0c;不会影响第一个变量&#xff1b;但对于复杂类型中的对象来讲&#xff0c;将一个对象赋值给另外一个对象&#xff0c;其实是将放对象内容的地址赋值给了第二个对象&#xff0…

Amazon EKS绑定alb 使用aws-load-balancer-controller(Ingress Controller)对外提供服务

1、创建AWS Load Balancer Controller 的 IAM 策略 亚马逊相关文档 下载地址 打开 策略 点击 创建策略 打开 IAM_Policy.json 复制内容粘贴到 json 点击下一步:标签 然后一直下一步 在下图中名称填写 AWSLoadBalancerControllerIAMPolicy 你也可以自定义名称。然后创建策略。…

尚医通_第11章_医院排班管理和搭建用户系统环境

尚医通_第11章_医院排班管理和搭建用户系统环境 文章目录尚医通_第11章_医院排班管理和搭建用户系统环境第一节、-医院排班管理需求分析一、医院排班管理需求1、页面效果2、接口分析第二节、医院排班管理-科室列表一、科室列表&#xff08;接口&#xff09;1、添加service接口和…

李峋同款爱心代码

李峋爱心代码背景代码运行pycharm打包成exe程序背景 最近大火的电视剧《点燃我温暖你》出现&#xff0c;令我的家庭地位进一步下降&#xff0c;因为男主“李峋”已经变成了她的大老公&#xff0c;而我就被打入冷宫. 为了满足她的“攀比心”&#xff0c;我连夜给她实现了粉红色爱…

第十节:多态【java】

目录 &#x1f340;1.多态 &#x1f4d6;1.1 多态的概念 &#x1f4d2;1.2 多态实现条件 &#x1f446;1.2.1向上转型 &#x1f4af;1.2.2重写 &#x1f531;1.2.3动态绑定和静态绑定 &#x1f308;1.2.4多态的应用 &#x1f447;1.2.5向下转型 &#x1f4d5;1.3多态的…

Java岗面试核心NIO有关知识总结

这篇文章主要是阅读了一些关于NIO的文章&#xff0c;对一些重要的部分进行了摘取总结。BIO、NIO、AIO的不同 BIO&#xff1a;同步阻塞IO模式&#xff0c;线程发起IO请求后&#xff0c;一直阻塞IO&#xff0c;直到缓冲区数据就绪后&#xff0c;再进行下一步操作。NIO&#xff1a…

SpringCloud基础知识【Hystrix熔断器】

SpringCloud基础知识【Hystrix熔断器】1. Hystrix概述2. Hystix-隔离2.1 线程池隔离2.2 信号量隔离2.3 Hystix隔离小结3. Hystix-降级3.1 服务提供方降级3.2 消费方降级3.3 Hystix降级小结4. Hystix-熔断4.1 代码演示4.1 熔断监控5. Hystix-限流1. Hystrix概述 Hystix&#xf…

基于概率距离削减法、蒙特卡洛削减法的风光场景不确定性削减(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

一文带你吃透数据库的约束,不做CRUD程序员

在SQL标准中&#xff0c;一共规定了6种不同的约束&#xff0c;包括非空约束&#xff0c;唯一约束和检查约束等&#xff0c;而在MySQL中是不支持检查约束的&#xff0c;所以这篇文章先对其余5种约束做一个详解和练习。 文章目录1. 约束的概念2. 约束的分类3. 非空约束4. 唯一约束…