蓝桥训练之前缀和与差分
配套视频链接
https://www.bilibili.com/video/BV1xq4y1y7Kz
一、前缀和
1.1什么是前缀和
前缀和是一种重要的预处理,能大大降低查询的时间复杂度。常常用于一些题目的优化,其实前缀和是一种思想,主要是维护离线区间信息的一种优化手段
最简单的一道题就是给定 n 个数和 m 次询问,每次询问一段区间的和。求一个 O(n + m) 的做法。
1.2一维前缀和
1.2.1问题引出
例题:http://acm.mangata.ltd/p/P1501
1.2.2思路
对于一维前缀和我们在输入数据的时候就能进行处理,假设前缀和数组是pre,那么我们的pre[i] = pre[i-1]+a[i]
,这样就维护了一个前缀,注意的是这里的i从1开始遍历
代码示例:
for(int i = 1;i <= n; ++i) {cin>>a[i];pre[i] = pre[i-1] + a[i];
}
这样我们就得到了一维前缀和的一个数组,那么这个数组可以干什么事呢?首先我们能在O(1)O(1)O(1)的时间复杂度内求出任一一个区间的和例如我们要求[L,R][L,R][L,R]区间和,即pre[R]-pre[L-1]
,
1.3一维前缀积
1.3.1问题引出
例题:https://ac.nowcoder.com/acm/contest/19483/A
1.3.2思路
由于有前缀和这种操作,我能能意识到这是一种思想,顺着这个思想我们能想到前缀积这个操作,和前缀和相似我们通过对pre数组进行乘法更新然后不断取模就能得到一个前缀积,如果我们想获得[L,R][L,R][L,R]的区间积那么需要用到逆元的操作即ans=pre[R]×inv(pre[L−1])ans = pre[R] \times inv(pre[L-1])ans=pre[R]×inv(pre[L−1])
代码示例:
pre[0] = 1;//否则全都变成0了
for(int i = 1;i <= n; ++i) {cin>>a[i];pre[i] = pre[i-1] * a[i] % mod;
}
求[L,R]区间内前缀积
ans = pre[R] * inv(pre[L-1]);
1.4 一维前缀异或
和上面类似,只不过维护的是异或和
1.5二维前缀和
1.5.1问题引出
例题:https://www.luogu.com.cn/problem/P2004
1.5.2思路
对于二维前缀和同理,我们从维护线前缀和变成了矩阵前缀和,换句话说就是从维护一维前缀和变成了维护二维前缀和。我们此时的pre[i][j]
表示的含义就是从左上角[1][1]
到右下角[i][j]
这个矩阵的一个和,因此我们能写出这样一个维护代码pre[i][j]=pre[i−1][j]+pre[i][j−1]−pre[i−1][j−1]+a[i][j]pre[i][j]=pre[i-1][j] + pre[i][j-1] - pre[i-1][j-1] + a[i][j]pre[i][j]=pre[i−1][j]+pre[i][j−1]−pre[i−1][j−1]+a[i][j],这个也是很好理解的,现在我们如果要求一个左上角为x1,y1x_1,y1x1,y1,右下角为x2,y2x_2,y_2x2,y2的矩阵和就可以这样写:ans=pre[x2][y2]−pre[x2][y1−1]−pre[x1][y2−1]+pre[x1−1][y1−1]ans=pre[x2][y2]-pre[x2][y1-1]-pre[x1][y2-1]+pre[x1-1][y1-1]ans=pre[x2][y2]−pre[x2][y1−1]−pre[x1][y2−1]+pre[x1−1][y1−1]
我们可以来看这样一张图:
对于粉色部分就是我们想要求得的矩阵范围,对于黄色,和棕色部分就是我们多余的范围,需要减去,但是在减的过程中会遇到减的区间重复的情况,所以我们需要加上pre[x1−1][y1−1]pre[x1-1][y1-1]pre[x1−1][y1−1]的操作
代码实现:
for(int i = 1;i <= n; ++i) {for(int j = 1;j <= m; ++j) {cin>>a[i][j];pre[i][j] = pre[i-1][j] + pre[i][j-1] - pre[i-1][j-1] + a[i][j];}
}
ans=pre[x2][y2]-pre[x2][y1-1]-pre[x1-1][y2]+pre[x1-1][y1-1];
1.5优缺点
优点很显然,就是能快速求出区间或者矩阵的一些信息例如和、积、异或等
缺点也很显然,就是不能在线操作,只能离线处理,遇到一个动态变化的就不能使用前缀和操作。
二、差分数组
2.1定义
对于已知有n个元素的离线数列d,我们可以建立记录它每项与前一项差值的差分数组fff:显然,f[1]=d[1]−0=d[1];f[1]=d[1]-0=d[1];f[1]=d[1]−0=d[1];对于整数i∈[2,n]i∈[2,n]i∈[2,n],我们让f[i]=d[i]−d[i−1]f[i]=d[i]-d[i-1]f[i]=d[i]−d[i−1]。
2.2性质
- 计算数列各项的值:观察d[2]=f[1]+f[2]=d[1]+d[2]−d[1]=d[2]d[2]=f[1]+f[2]=d[1]+d[2]-d[1]=d[2]d[2]=f[1]+f[2]=d[1]+d[2]−d[1]=d[2]可知,数列第iii项的值是可以用差分数组的前iii项的和计算的,即d[i]=f[i]d[i]=f[i]d[i]=f[i]的前缀和。
- 第iii项的前缀和即为数列前iii项的和
通过以上两点性质我们能在O(N)O(N)O(N)的时间复杂度内求出区间和以及每个位置的值,带来的好处就是能快速处理区间加减操作
2.3使用
对于区间[L,R][L,R][L,R]的增加一个x,那么在差分数组上我们进行的操作就是f[L]+x,f[R+1]−xf[L]+x,f[R+1]-xf[L]+x,f[R+1]−x,为什么呢?我们来回顾一下对于差分数组求前iii项前缀和求出来的就是d[i]d[i]d[i],那么我们在f[L]f[L]f[L]的位置进行一个加法操作也就是让从L这个位置开始的后面所有的d进行一个+x的操作,对于F[R+1]−xF[R+1]-xF[R+1]−x其实就是让R+1到后面所有元素减去x,因为前面在L这个位置进行了以后所有元素+x这个操作
这样一来区间修改再求单点的值或者区间值的话复杂度就是O(N)O(N)O(N)的,其实到后面我们会去学习一种数据结构->树状数组,我们利用差分这个性质的话,在O(logn)O(log_n)O(logn)的时间复杂度就能求到单点和区间值,现在我们就不做探究了,其实差分重要的不是差分数组,而是差分思维。
练习题单
洛谷题单:https://www.luogu.com.cn/training/200
牛客:https://ac.nowcoder.com/acm/contest/19483
牛客的BCD可能有点难,可以不用去做
蓝桥训练之前缀和与差分相关推荐
- 蓝桥杯JAVA-28.前缀和与差分详解
个人博客 www.tothefor.com 蓝桥杯复习知识点汇总 目录 开始之前,推荐先看一下总结.再看内容.也许会帮你更好的理解. 前缀和是指某序列的前n项和,可以把它理解为数学上的数列的前n项和, ...
- 前缀和,差分算法训练
知识点: 一维前缀和 二维前缀和 一维差分 二维差分 题目: 蓝桥杯2017初赛-k倍区间-前缀和 [蓝桥杯2018初赛]递增三元组-双指针,枚举,排序,前缀和
- 0x03.基本算法 — 前缀和与差分
目录 一.前缀和 二.二维前缀和 1.二维前缀和的修改和求和 0. NOI 2003激光炸弹(二维前缀和) 1.牛妹吃豆子(二维前缀和模板,修改+求和) 2.静态数组的区间求和问题 3.静态维护区间加 ...
- 基本算法之前缀和与差分的是使用
前缀和与差分 前缀和 鸣谢 二维前缀和 激光炸弹 差分 求差分 差分求区间修改 增减序列 最高的牛 前缀和 鸣谢 添加链接描述 和 添加链接描述 二维前缀和 激光炸弹 题目链接 解题思路: 解法思路: ...
- 前缀和与差分的使用(新手快速入门)
前缀和 前缀和定义:s[0]=0; s[i]=s[i-1]+a[i]; 其中s[i]数组为a[i]数组的前缀和: 有了前缀和后,给定一个区间 [l,r] 的和就可以表示为: sum=s[r] -s[l ...
- 信奥中的数学:前缀和与差分、大整数开方技巧
[算法2-1]前缀和与差分 [算法2-1]前缀和与差分 - 题单 - 洛谷 前缀和与差分 图文并茂 超详细整理(全网最通俗易懂) 前缀和与差分 图文并茂 超详细整理(全网最通俗易懂)_林深不见鹿 的博 ...
- 基本算法——前缀和与差分
一.前缀和 一维前缀和 顾名思义,不再赘述. #include <iostream> #include <cstdio> #include <algorithm> ...
- c++算法基础必刷题目——前缀和与差分
文章目录 前缀和与差分算法: 1.校门外的树 2.值周 3.中位数图 4.激光炸弹 5.二分 6.货仓选址 前缀和与差分算法: 前缀和与差分算法主要是为了快速求出某个区间的和,例如有一个数组a[1 ...
- 前缀和与差分——最大加权矩形
前缀和与差分--最大加权矩形 题目描述 为了更好的备战 NOIP2013,电脑组的几个女孩子 LYQ,ZSC,ZHQ 认为,我们不光需要机房,我们还需要运动,于是就决定找校长申请一块电脑组的课余运动场 ...
最新文章
- [Head First设计模式]身边的设计模式——适配器模式
- matlab创建图形用户界面,Matlab 用户图形界面 基础 (一)
- 添加当前文件夹及其子文件夹到以及别而的文件夹到当前路径
- Python基础练习题:猜数字小游戏
- spring boot中data truncation data too long for column问题
- Erlang与java的内存架构比较
- Python2 之 print函数示例
- 分享一个关于网站适应性的解决方案
- 【请教】服务器上出现的两个问题!
- shell 数据类型
- android开发app初始化,Android 的 Application 初始化
- AndroidDeveloper Weekly No.5
- FISCO BCOS源码(5)基本概念
- java过滤空号了停机号_手机空号、停机、注销,空号检测为你去除无效号码
- erphpdown9.2.7前台会员中心美化模板
- wifi情况下使用fiddler_如何对手机http进行抓包?Fiddler工具超好用
- PCA与2DPCA及2D-2DPCA零基础理解(下)
- linux mysql搭建禅道详细教程_2019-08-28 redhat linux如何部署禅道服务器(一键安装包)...
- hdu6608 Fansblog(威尔逊定理)
- 阿里的互联网三高架构是真的牛!腾讯百度根本模仿不来
热门文章
- Matlab二维曲线之fplot函数
- hibernate.validator验证参数
- C#Const与static readonly的区别
- vue双向数据绑定的简单实现
- java 读CSV 和 Excel
- Java中导入Excel文件
- 计算机网络总结 第一章 计算机网络概论
- 从0开始搭建SQL Server AlwaysOn 第一篇(配置域控)
- ERROR: ld.so: object '/usr/lib64/libtcmalloc.so.4' from LD_PRELOAD cannot be preloaded: ignored
- 计算机组成一简化模型