当前位置: 首页 > news >正文

一维前缀和/差分,二维前缀和/差分

纯纯笔记,不详细不详细

代码不是题解不全是题解(是题解的能ac)

一维:

前缀和:

预处理,算出从1到 i 所有数的总和

使用场景:

在查询某一区间,如:查询 arr数组中 从 下标left 到 下标 right 的 的所有数值之和

1.如果不使用前缀和,暴力循环,时间复杂度为 o(1)(遍历数组,从left遍历到right),这样有很多次重复计算。

2.如果使用前缀和,查询时时间复杂度为 o(1),即一次查询就算出了要求区间内的数值总和,

查询时 sum[right]-sum[left-1] 

#include <iostream>
using namespace std;
int sum[1000005];
int arr[1000005];//可以不创建arr数组,因为arr[i]每个位置的数字都只用了一次->用于计算sum[i]
int main()
{   int n = 0, a = 0;cin >> n;for(int i = 1; i <= n; i++){cin>>arr[i];sum[i] = sum [i-1] + arr[i];}cin >> left >> right;cout << sum[right] - sum[left-1];return 0;
}

一维差分练习:

洛谷P8218

差分:

前缀和的逆运算

使用场景:

(假设仍有 arr[100005] 数组)

差分用于同时对 (arr[1000005] )数组某一区间的数值进行操作,而不必暴力循环

例如:对arr[x]到arr[y]同时加上某一数值z

1.构建差分数组

构建arr[]的差分数组brr[]

brr[i]=arr[i]-arr[i-1](i从1开始,arr[0]=0=brr[0])

brr[1]~brr[i]的 前缀和 等于 arr[i],例如:

        arr[1]=brr[1](+brr[0],brr[0]=0)

        arr[2]=brr[2]+brr[1] ~~~~~ = brr[2]+arr[1]

        arr[3]=brr[3]+brr[2]+brr[1] ~~~~~ brr[3]+arr[2]

        ......

        arr[i]=brr[i]+arr[i-1]

2.原理

假设要对arr数组的 [l,r] 区间内所有值同时加上z,

1>首先,对brr[l]+z

这时如果 再使用brr[1]~brr[i]求前缀和,得新的arr[]数组

这等效于对arr[l]~arr[i]所有数值都加z

但现在不求brr的前缀和

2>然后,对brr[r+1]-z

这等效于对arr[r+1]~arr[i]所有数值减z

这时如果 再使用brr[1]~brr[i]求前缀和,得新的arr[]数组

这等效于对arr[l]~arr[i]所有数值都加z

现在对求brr的前缀和,得到的结果的就是对arr[l,r]区间内所有值+z的结果

#include <iostream>
using namespace std;
int main()
{int n = 0, p = 0, i = 0, j = 0;int x = 0, y = 0, z = 0;cin >> n >> p;for (i = 1; i <= n; i++){cin >> arr[i];brr[i] = arr[i] - arr[i - 1];}cin >> x >> y >> z;brr[x] += z;brr[y + 1] -= z;for (i = 1; i <= n; i++) {arr[i] = brr[i] + arr[i - 1];}return 0;
}

一维差分练习

洛谷P2367 语文成绩

二维:

二维稍微复杂一些,配图片更容易理解,但是这里大概率没有(

前缀和:

定义数组arr[][],sum[][]

arr[][]储存输入数据

sum[][]储存arr[][]前缀和

sum[i][j]的意义是左上角为arr[1][1]~右下角为arr[i][j]的矩形区间内数值的前缀和

使用场景:

多次对某一个二维区间内数值求和(仅进行一次求和操作,之后只进行查询操作)

递推sum公式:

把左上角为arr[1][1]~右下角为arr[i][j]的矩形区间分为四个小矩形区间

(便于理解,不对arr数组真的操作)

                区间1>arr[1][1]~右下角为arr[i][j-1]

                区间2>arr[1][1]~右下角为arr[i-1][j]

                区间3>arr[1][1]~右下角为arr[i-1][j-1]

                区间4>arr[i][j]~右下角为arr[i][j],其实就是arr[i][j]

        最大矩形的前缀和=(区间1.左+区间2.上-区间3.左上)前缀和 + 区间4.右下角单个arr[i][j]数值

        sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+arr[i][j]

#include <iostream>
using namespace std;
int arr[121][121];
int sum[121][121];
int main()
{int n = 0, i = 0, j = 0, x = 0, y = 0;int max = -0x7f7f7f, t = 0;cin >> n;for (i = 1; i <= n; i++)for (j = 1; j <= n; j++){cin >> arr[i][j];sum[i][j]+= sum[i - 1][j]+ sum[i][j - 1]- sum[i - 1][j - 1]+ arr[i][j];}for (i = 1; i <= n; i++)for (j = 1; j <= n; j++)for (x = i; x <= n; x++)for (y = j; y <= n; y++){t = sum[x][y]- sum[x][j - 1]- sum[i - 1][y]+ sum[i - 1][j - 1];if (max < t)max = t;}cout << max;return 0;
}

二维前缀和练习:

洛谷P1719最大加权矩阵

差分:

二维前缀和的逆运算

使用场景:

对二维区间内某一数值进行批量操作

初始化差分数组不太方便,可以假想在一个 全0的二维矩阵(设为crr[][]) 上操作,最后将变换后的crr[][]与原arr[][]做矩阵加法

二维差分数组与一维差分数组的相似之处:

(定义原数组arr[N][N],差分数组brr[N][N]])

对二维差分数组操作时,假设对brr[i][j]+z,等同于对arr[i][j]~arr[N][N]所有数+z

使用场景,具体操作:

对某一区间(如左上角arr[i][j]~右下角arr[x][y])内数据全部+z

1>(便于理解,不真的对arr数组进行操作)

把左上角arr[i][j]~右下角arr[N][N]大矩形区间分为四个小矩形区间

                区间1>arr[i][j]~右下角为arr[x][y]

                区间2>arr[i][y+1]~右下角为arr[N][N]

                区间3>arr[x+1][j]~右下角为arr[N][N]

                区间4>arr[x+1][y+1]~右下角为arr[N][N]

        直接对全零矩阵进行操作,不考虑初始化br人, 现在brr也是全0矩阵

(可以认为brr是全零矩阵的差分数组)

        brr[i][j] += z

        brr[i][y+1] -= z

        brr[x+1][j] -= z

        brr[x+1][y+1] += z

2>对brr求前缀和,即二维数组前缀和,得到将全零矩阵进行变换后的新矩阵

3>新矩阵和原矩阵arr相加

#include<iostream>
using namespace std;
int arr[1005][1005];
int main()
{int m = 0, n = 0;int i = 0, j = 0;int x1 = 0, y1 = 0, x2 = 0, y2 = 0;cin >> n >> m;while (m--){cin >> x1 >> y1 >> x2 >> y2;arr[x1][y1]++;arr[x1][y2 + 1]--;arr[x2 + 1][y1]--;arr[x2 + 1][y2 + 1]++;}for (i = 1; i <= n; i++){for (j = 1; j <= n; j++){arr[i][j] = arr[i][j] + arr[i - 1][j] + arr[i][j - 1] - arr[i - 1][j - 1];cout << arr[i][j] << ' ';}cout << endl;}return 0;
}

二维差分练习:

P3397 地毯


http://www.mrgr.cn/news/71844.html

相关文章:

  • Kafka--关于broker的夺命连环问
  • Go语言中的`os.WriteFile`:简单高效的文件写入方法
  • 008_SSH_Sqlserverl图书管理系统(学生注册 借书 还书)_lwplus87(免费送)
  • ssm083化妆品配方及工艺管理系统的设计与实现+jsp(论文+源码)_kaic
  • qt QWebSocketServer详解
  • 7.qsqlquerymodel 与 qtableview使用
  • 【时时三省】(C语言基础)函数介绍strtok
  • 概率论中的PMF、PDF和CDF
  • 关于CJS,AMD,CMD,UMD的了解
  • 推荐一款强大的行车记录仪播放器:Dashcam Viewer Plus
  • Java小型项目-音乐评论分析
  • 论文解读:CARAT
  • cache(五)Write-through,Write-back,Write-allocate,No-write-allocate
  • 【t365】基于springboot的高校疫情防控系统
  • uniapp路由与页面跳转详解:API调用与Navigator组件实战
  • linux性能提升之sendmmsg和recvmmsg
  • kafka夺命连环三十问(16-22)
  • A/B测试的误区与优化策略:如何最大化客户留存ROI?
  • 【LeetCode】【算法】136. 只出现一次的数字
  • 数据结构《链表》
  • ML 系列: 第 23 节 — 离散概率分布 (多项式分布)
  • 【MySQL 保姆级教学】事务的自动提交和手动提交(重点)--上(13)
  • 移动电源测试中最核心的测试项目有哪些?-纳米软件
  • 多线程和线程同步复习
  • 鸿蒙next版开发:ArkTS组件通用属性(Flex布局)
  • python语言基础-4 常用模块-4.7 pyinstaller模块