基本算法-差分 模板+习题

目录

前言

1.一维差分讲解

2.差分模板

3.差分模板讲解 

二、习题

1.题目来源

2.题目描述:

3.题目讲解:

4.完整代码:

5.代码讲解: 

总结


前言

差分算法是一种处理数字序列或函数的方法,其主要思想是通过对序列中的元素进行差分运算来获取序列的性质。这种算法在许多领域都有应用,包括计算机科学、数据分析、信号处理等。

在计算机科学中,差分算法通常用于解决动态规划问题。通过将原始问题分解为更小的子问题,并利用子问题的解来构造原问题的解,差分算法可以有效地降低问题的复杂度。

差分是前缀和的逆运算,它们之间的关系就好比积分和求导。它们都是一种小技巧,在算法比赛中使用广泛。


一、模板

1.一维差分讲解

一维差分,顾名思义,就是对一维数组(线性数组)中相邻元素的差值进行计算的一种方法。一维差分的公式如下: 假设我们有一个一维数组A,长度为n,其元素为A[0], A[1], ..., A[n-1]

我们想要计算其差分数组D,其中D[i]A[i]A[i-1]的差值,即D[i] = A[i] - A[i-1]。 差分数组D的长度也是n,其元素为D[0], D[1], ..., D[n-1]

根据差分的定义,我们可以得到以下公式:

1. 如果i == 0,那么D[i] = A[i] - A[i] = 0

2. 如果i > 0,那么D[i] = A[i] - A[i-1]

差分数组D的生成过程可以概括为:

1. 初始化D[0] = A[0]

2. 对于i从1到n-1,计算D[i] = A[i] - A[i-1]这就是一维差分的基本公式。

通过差分,我们可以更方便地分析和处理一维数组。

2.差分模板

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

3.差分模板讲解 

这段代码是一个C++函数,名为`insert`,它接受三个参数:整数`l`、整数`r`和整数`k`。该函数的功能是在数组的`l`位置插入一个值为`k`的元素,然后在`r+1`位置删除一个值为`k`的元素。

这段代码的主要操作是在差分数组`b`上进行的。差分数组`b`与原数组`a`的关系为: b[i] = a[i] - a[i-1]

其中,a[i]是原数组中的第i个元素,b[i]是差分数组中对应的元素。

现在,让我们分析一下`insert`函数中的操作:

1. b[l]+=k:在差分数组`b`的第`l`个位置加上`k`,相当于在原数组的`l`位置插入一个值为`k`的元素,并保持其他位置的元素值不变。

2. b[r+1]-=k:在差分数组`b`的第`r+1`个位置减去`k`,相当于在原数组的`r+1`位置删除一个值为`k`的元素,并保持其他位置的元素值不变。 通过这种方式,我们可以在不修改原数组的情况下,在指定位置插入或删除元素。

了解思想了吧,快去下面习题想想怎么做吧!

二、习题

1.题目来源

P2367 语文成绩 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

2.题目描述:

3.题目讲解:

根据题目,给区间的元素加上z,可知此题要利用差分来写。代码讲解中,有详细解释利用模板。

4.完整代码:

#include<bits/stdc++.h>
using namespace std;

const int N=5e6+10;
int a[N],b[N];

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

int main(){
  int n,p,c=1e10;
  cin>>n>>p;
  for(int  i=1;i<=n;i++) scanf("%d",&a[i]);

  for(int i=1;i<=n;i++) insert(i,i,a[i]);
  while(p--){
    int x,y,z;
    scanf("%d%d%d",&x,&y,&z);
    insert(x,y,z);
  }
  for(int i=1;i<=n;i++){
    b[i]+=b[i-1];
    if(b[i]<c) c=b[i];
  }
  cout<<c<<endl;
  return 0;
}

5.代码讲解: 

差分数组构造:

  for(int i=1;i<=n;i++) insert(i,i,a[i]);

差分数组b与原数组a的关系是:b[i] = a[i] - a[i-1]。也就是说,b[i]是原数组中第i个元素与第i-1个元素之差。

因此,当我们调用insert(i,i,a[i])时,实际上是在差分数组b的i位置插入了a[i],在i+1位置插入了-a[i]。这样,原数组a的每个元素都被插入到差分数组b中,从而得到差分数组b。

 利用差分数组实现x-y区间加上z的操作:

  while(p--){
    int x,y,z;
    scanf("%d%d%d",&x,&y,&z);
    insert(x,y,z);
  }

实现题目全部操作后数组a的全部元素大小并找出最小值:

  for(int i=1;i<=n;i++){
    b[i]+=b[i-1];
    if(b[i]<c) c=b[i];
  }

 b[i]+=b[i-1]等于操作实现后的数组元素大小,原因:

A[i] = D[1] + D[2] + ... + D[i]

因为D[0] = A[0],所以实际上,A[i] = D[0] + D[1] + ... + D[i]

因此,差分序列的累加和,即D[0] + D[1] + ... + D[i],正好等于原数组的大小。

讲解结束啦,谢谢观看!


总结

差分是一个比较好用的技巧,在算法比赛中,常常要考到。

呃呃呃?要不给作者一个赞和收藏,嘿嘿,在顺手点个关注?(有些厚颜无耻了)

感谢友友们交流,以及欢迎友友们评论!非常感谢大家阅读!让我们一起努力学习算法吧。

代码能力是练习出来的,不是看出来的,快去练习!!!

  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不想敲代码的小趴菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值