2024-01-21 11:32阅读: 8评论: 0推荐: 0

(坚持每天写算法)算法复习与学习part1基础算法part1-11——差分

  差分和前缀和是有联系的。

  首先给定一个原数组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数组是需要自己构造的,而构造b数组的方法最简单直接的是:

  a[0 ]= 0;

  b[1] = a[1] - a[0];

  b[2] = a[2] - a[1];

  b[3] =a [3] - a[2];

  ........

  b[n] = a[n] - a[n-1];

  差分可以应用的问题:

  给定区间[l ,r ],让我们把a数组中的[ l, r]区间中的每一个数都加上c,即 a[l] + c , a[l+1] + c , a[l+2] + c ,,,,,, a[r] + c;

  使用差分,我们可以这么做:

  首先让差分b数组中的 b[l] + c ,a数组变成 a[l] + c ,a[l+1] + c,,,,,, a[n] + c;

  然后我们打个补丁,b[r+1] - c, a数组变成 a[r+1] - c,a[r+2] - c,,,,,,,a[n] - c;

  这样子就可以得到上述问题的求解。

  这个是题解:

   这里是代码:

复制代码
//差分 时间复杂度 o(m)
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
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]);
        b[i] = a[i] - a[i - 1];      //构建差分数组
    }
    int l, r, c;
    while (m--)
    {
        scanf("%d%d%d", &l, &r, &c);
        b[l] += c;     //将序列中[l, r]之间的每个数都加上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;
}
复制代码

  补充:前缀和和差分的题目,可以在写的时候直接浮现图解就可以确定下标。

  其实差分不止是这一种,因为前缀和都有两种,一维和二维。

  二维的差分数组,也是同一个道理,a[i][j] = b[1][1] + ……+b[i][j],a数组是b数组的前缀和数组。

  在二维中,某一段区间用下面的图来表示的话就是以(x1,y1)为左端点,(x2,y2)为右端点的矩形。

  二维利用差分想让某一段区间的a都加上某一个值,有点难说,建议画一个表示b数组的图还有一个表示a数组的图,还有一个表示这里是图解:

  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,才能使其恢复。

  (注意,x是行,y是列,不要看成函数了,要不然解不出来)

  (还有的就是,是b[x2+1][y1]而不是b[x2][y1],因为如果选择了后者边界这些a数组是不会加c,而事实上a[x2][y2]也是边界上的。)

  这个是代码;

复制代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;

int n, m , q;
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(){
    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 ++){
            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 ++){
            b[i][j] += b[i-1][j] + b[i][j-1] - b[i-1][j-1];//其实这里是求a,b的前缀和是a
        }
    }
    
    for(int i = 1 ; i <= n ; i ++){
        for(int j = 1 ; j <= m ; j++){
            printf("%d " , b[i][j]);
        }
        puts(" ");//发现要空行系统才能识别
    }
    
}
复制代码

  参考链接:AcWing 797. 差分 【c++详细题解】 - AcWing(写的是真的好)

  时间复杂度:O(n)和O(n^2)

本文作者:程序计算机人

本文链接:https://www.cnblogs.com/clina/p/17977662

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   程序计算机人  阅读(8)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 Lions Pride Audio artist
  2. 2 Salty Sailor David Arkenstone
  3. 3 Stonefire David Arkenstone
Salty Sailor - David Arkenstone
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

Not available