差分

简介: 复习acwing算法基础课的内容,本篇为讲解基础算法:差分,关于时间复杂度

文章目录

前言

一、差分,差分数组

1.什么是差分,差分数组

2.如何得到差分数组

3.差分数组的作用

二、一维差分与二维差分

1.一维差分

一维差分模板

例一:AcWing797. 差分

AC代码

2.二维差分

二维差分模板

例二:AcWing798. 差分矩阵

AC代码

三、时间复杂度


前言

复习acwing算法基础课的内容,本篇为讲解基础算法:差分,关于时间复杂度:目前博主不太会计算,先鸽了,日后一定补上.


一、差分,差分数组

1.什么是差分,差分数组

差分可以看做前缀和的逆运算,同前缀和一样,差分数组从1号位置点开始,假设我们有一个原数组a:a[1], a[2], a[3] … a[i],我们需要构造出一个数组b:b[1], b[2], b[3] … b[i],使得 a[i] = b[1] + b[2] + b[3] + … + b[i],即数组a是数组b的前缀和数组,即每一个a[i] 都可以对b数组从 1 ~ i 求前缀和得到

2.如何得到差分数组

这一步的操作有点像高中数列中的叠加法的逆运算:

image.png

对于a[0],把数组a全局定义即可。


3.差分数组的作用

对于这么一种情况,我们可以利用差分数组来快速解题:将数组a的[l, r]这一区间内加上一个常数c,最暴力的做法:利用for循环遍历a数组,并在[l, r]区间内加上c,如果有m次操作,这样下来的时间复杂度为O(n * m),差分则是对这一步骤的优化。


难点:我们要明确数组a是数组b的前缀和数组,即数组b的[1 ~ i]个元素的和等于 a[i],故如果我们对b数组的某一项加上c,比如在b[2]加上一个常数c,数组b中的剩余元素不进行处理,这一操作的结果是对于数组b而言只是把b[2]变成b[2] + c,而反应到数组a上,对数组b求前缀和得到数组a,所以当b[2]发生改变后a数组从a[2] ~ a[n]都加上了常数c,如果还没有理解的话,这里给出一个例子帮助理解:


image.png

image.png

同理,我们如果让 b[2] 减去一个常数c的话,那么对于b的前缀和数组a而言,从a[2]开始到a[n]全部都会减去一个数c,那么我们利用差分数组b的这一性质,就可以通过改变数组b的两个元素的值,就可以实现将数组a的 [l, r] 这一区间加上或者减去一个数,例:我们欲将数组a的[2~7]这一区间内加上一个数6,具体实现为:

b[2] += 6, b[8] -= 6;

即从a[2]开始以后的每一项都加上一个6,从a[8]开始以后的每一项都减去一个6,那么对于a[8]和之后的所有元素,同时加上减去一个相同的数,相当于未发生改变,而对于a[2] ~ a[7]这一段区间,加上了一个6.


二、一维差分与二维差分

1.一维差分

在一、差分,差分数组中已经介绍了一维差分,这里不做过多赘述,直接上模板和例题


一维差分模板

我们要将一个数列a的[l, r]范围内加上(或减去)一个数c,可对a的差分数组b进行如下操作

b[l] += c, b[r + 1] -= c;

例一:AcWing797. 差分

本题链接:AcWing797. 差分

本博客给出本习题截图:

image.png

AC代码

#include <cstdio>
using namespace std;
const int N = 100010;
int a[N], b[N];
int main()
{
    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];       //b为a的差分数组
    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 ++ ) b[i] += b[i - 1];            //计算前缀和
    //此时的b数组就是前缀和数组了,即要输出的变化后的数组a
    for (int i = 1; i <= n; i ++ ) printf("%d ", b[i]);
    return 0;
}

2.二维差分

二维差分的分析思路其实和二维前缀和类似,如图:

image.png

二维差分模板

现我们想让如图中黄色部分加上一个常数c,进行如下操作

b[x1][y1] += c;          //从(x1,y1)坐标往右下角走,所有的数都加一个c
b[x1][y2 + 1] -= c;      //从(x1,y2 + 1)坐标往右下角走,所有数都减一个c
b[x2 + 1][y1] -= c;      //从(x2 + 1,y1)坐标往右下角走,所有数都减去一个c
b[x2 + 1][y2 + 1] += c;  //从(x2 + 1,y2 + 1)坐标往右下角走,所有数都加上一个c(因为被多减去一个c)

例二:AcWing798. 差分矩阵

原题链接:AcWing798. 差分矩阵

本博客给出题目截图:

image.png

image.png

AC代码

#include <cstdio>
using namespace std;
const int N = 1010;
int a[N][N], b[N][N];
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;
}
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 ++ )
            insert(i, j, i, j, a[i][j]);
    while (q -- )
    {
        int x1, x2, y1, 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 ++ )
            b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];  //求前缀和,即操作后的a
    for (int i = 1; i <= n; i ++ )
    {
        for (int j = 1; j <= m; j ++ )
            printf("%d ", b[i][j]);
        puts("");
    }
    return 0;
}

三、时间复杂度

关于差分的时间复杂度以及证明,后续会给出详细的说明以及证明过程,目前先鸽了。

目录
相关文章
|
6月前
|
人工智能 移动开发
差分题练习(区间更新)
差分题练习(区间更新)
|
4月前
|
人工智能 算法 JavaScript
【算法】前缀和与差分
算法学习——前缀和与差分(含一维和二维)
52 4
【算法】前缀和与差分
|
传感器
全差分运算放大器
全差分运算放大器(Fully Differential Operational Amplifier,简称FDA)是一种特殊的运算放大器,具有两个差分输入和两个差分输出。它的输入和输出均为差分信号,可以用于放大差分信号、抑制共模信号、降低噪音等。
199 0
|
人工智能 BI
【差分数组】
【差分数组】
|
算法
通过白噪声的频谱处理产生任意光谱斜率(f^a)噪声(Matlab代码实现)
通过白噪声的频谱处理产生任意光谱斜率(f^a)噪声(Matlab代码实现)
|
11月前
差分方程模型:蛛网模型
差分方程模型:蛛网模型
212 0
|
移动开发 人工智能 算法
【算法基础】差分算法及其应用
【算法基础】差分算法及其应用
193 0
|
机器学习/深度学习 传感器 算法
【温度场分析】基于差分方程二维钢板冷却温度场分析附Matlab代码
【温度场分析】基于差分方程二维钢板冷却温度场分析附Matlab代码
|
人工智能 算法 BI
基础算法-差分矩阵
基本思路 如果将差分可以看作是一维差分,那么差分矩阵便是二维差分,与二维前缀和也就是子矩阵的和相对应,互为逆运算。