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

基础算法 —— 前缀和 【复习总结】

1. 简介

前缀和是经典的用空间换时间的方法,它的核心思想是预处理,可以在枚举过程中,快速给出查询结果。后文我们会遇到一维前缀和二维前缀和

它们的处理方法都可以分为两步:1. 创建前缀和数组;2. 查询目标区间

2. 一维前缀和

2.1 模板

1. 套用公式创建前缀和数组:f[i] = f[i-1] + a[i] (此处,原数组为 a,前缀和数组为 f 。f[i] 表示:a 数组 [1,i] 区间所有元素的和)

2. 查询区间 [ l,r ] 的和:f[r]-f[l-1]

2.2 最大子段和

2.2.1 题目描述

给出一个长度为 n 的序列 a,选出其中连续且非空的一段使得这段和最大(1<=n<=2e5)

输入描述:

第一行是一个整数,表示序列的长度 n。

第二行有 n 个整数,第 i 个整数表示序列的第 i 个数字 ai​ (-1e4<=ai<=1e4)

输出描述:

一行一个整数表示答案

输入:

7
2 -4 3 -1 2 -4 3
输出:

4

2.2.2 算法分析

因为要选出连续的一段,我们可以考虑以 i 位置元素 a[i] 结尾的最大子段和就是结果。而这个子段和相当于我们用前缀和 f[i] 减去 i 位置前的某个位置 f[x],要想让这个字段和最大,那么 f[i] 要减去最小的 【前驱子段】。

所以,我们可以创建 a 数组的前缀和数组 f ,在遍历 f 数组的过程中,更新 【当前位置为结尾的最大子段和】同时更新 【前驱子段最小值】

2.2.3 代码实现

#include<iostream>
using namespace std;
const int N = 2e5 + 10;
typedef long long LL;
LL f[N];
int n;int main()
{cin >> n;for (int i = 1; i <= n; i++){//创建前缀和数组int x; cin >> x;f[i] = f[i - 1] + x;}//标记最大子段和,初始为负无穷(如果为0可能会干扰结果)LL ret = -1e9;//【最小前驱子段和】初始为0,因为如果前缀和下标为1,不存在前驱子段LL premin =0;for (int i = 1; i <= n; i++){//更新最大子段和ret = max(ret, f[i]-premin);//更新【最小前驱子段和】premin = min(premin, f[i]);}cout << ret << endl;return 0;
}

3. 二维前缀和

3.1 模板

1. 套用公式创建前缀和矩阵:f[i][j] = f[i-1][j] + f[i][j-1] - f[i-1][j-1] + a[i][j] (此处,原数组为 a,前缀和矩阵为 f 。f[i][j] 表示:a 矩阵左上角 [1,1] ,到右下角 [i][j] 所有元素的和)

2. 查询 (x1,y1) 为左上角,(x2,y2)为右下角的子矩阵的和

3.2 激光炸弹

3.2.1 题目描述

一种炸弹摧毁一个边长为 m 的正方形内的所有目标。现在地图上有 n 个目标,用整数 xi​ , yi​ 表示目标在地图上的位置,每个目标都有一个价值 vi​。激光炸弹有一个缺点,就是其爆破范围,即那个边长为 m 的边必须与 x 轴,y 轴平行。若目标位于爆破正方形的边上,该目标不会被摧毁。

现在你的任务是计算一颗炸弹最多能炸掉地图上总价值为多少的目标。

可能存在多个目标在同一位置上的情况。

输入描述:

输入的第一行为整数 n 和整数 m;(1<=n<=1e4,1<=m<=5e3)

接下来的 n 行,每行有 3 个整数 x,y,v,表示一个目标的坐标与价值。

输出描述:

输出仅有一个正整数,表示一颗炸弹最多能炸掉地图上总价值为多少的目标(结果不会超过 32767 )。

输入:

2 1
0 0 1
1 1 1
输出:

1

3.2.2 算法分析

根据题目,我们可以先使用一个二维矩阵将每个位置的价值叠加起来,即 a[i][j] 表示位置 [i,j] 的所有目标价值之和。因为激光炸弹获得的价值正好是 R*R 的矩阵所有目标价值的和,所以可以使用二维前缀和快速求出矩阵的和,枚举所有变长为 R 的矩阵的和(只需枚举右下角(x2,y2),左上角为(x2-R+1,y2-R+1)),选出最大值即可

3.2.3 代码实现

#include<iostream>
using namespace std;
const int N = 5010;int a[N][N];
//前缀和数组
int f[N][N];
int n, m;int main()
{cin >> n >> m;while (n--){int x, y, v; cin >> x >> y >> v;//下标从 1 开始x++, y++;//同一个位置所有目标价值叠加a[x][y] += v;}//矩阵的范围n = 5001;for (int i = 1; i <= n; i++){for (int j = 1; j <= n; j++){//用模板求前缀和f[i][j] = f[i - 1][j] + f[i][j - 1] + a[i][j] - f[i - 1][j - 1];}}int ret = 0;//如果边长大于区域,相当于摧毁整个区域m = min(m, n);//枚举所有变长为 m 的矩阵//注意右下角从(m,m) 开始for (int x2 = m; x2 <= n; x2++){for (int y2 = m; y2 <= n; y2++){//求左上角int x1 = x2 - m + 1, y1 = y2 - m + 1;//得到最大值ret = max(ret, f[x2][y2] - f[x1 - 1][y2] - f[x2][y1 - 1] + f[x1 - 1][y1 - 1]);}}cout << ret << endl;return 0;
}

相关文章:

  • [特殊字符] KoalaAI 1.0.23 震撼升级:GPT-4.1免费畅享,AI革命触手可及!
  • Node.js 操作 MySQL 数据库
  • MySQL:存储函数和存储过程
  • 基于vue2+ElementUI的el-tree封装一个带搜索的树形组件
  • 【差分隐私相关概念】瑞丽差分隐私(RDP)-瑞丽散度约束了贝叶斯因子后验变化
  • 前端与Java后端交互出现跨域问题的14种解决方案
  • 使用 Node.js、Express 和 React 构建强大的 API
  • 4.15【A】pc homework3~
  • python实战案例:玩具销售数据分析
  • Java基础-泛型(泛型擦除)
  • 【redis】初识redis
  • 实验二.单按键控制LED
  • 自定义Jackson序列化和反序列化
  • 家用发电机的原理是什么?
  • 【STM32】在FreeRTOS下使用硬件SPI收发数据出现的时序耦合问题(WK2124芯片为例)
  • 使用 Sass 打造动态星空背景效果
  • 远方游子的归家记:模仿美食网页的制作与实现
  • React JSX?
  • C++红黑树
  • 时间的重构:科技如何重塑人类的时间感知与存在方式
  • 融创中国:今年前4个月销售额约112亿元
  • 洞天寻隐·学林纪丨玉洞桃源:仇英青绿山水画中的洞天与身体
  • 绍兴柯桥:用一块布托起中国制造的新经纬
  • 北约年度报告渲染所谓“中国核威胁”,国防部回应
  • 央行:5月8日起7天期逆回购操作利率由此前的1.50%调整为1.40%
  • 江西省文化和旅游厅厅长梅亦已任省委宣传部副部长