| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 数据结构与算法 -> 蓝桥杯AcWing学习笔记 2-2前缀和的学习(附相关蓝桥真题:K倍区间)(Java) -> 正文阅读 |
|
[数据结构与算法]蓝桥杯AcWing学习笔记 2-2前缀和的学习(附相关蓝桥真题:K倍区间)(Java) |
蓝桥杯前缀和
一维前缀和假设一个数组a的区间为[L, R],全部遍历一遍的话时间复杂度是O(N)
如果我们需要求很多次的话就可能会超时,那么前缀和就可以快速的让我们算出来某一个区间内所有数的和。 思想: 我们重新预处理一个新的数组:s[i]= a[1] + a[2] + … + a[i],s[i]是原数组前i个数的和,特殊规定s[0] = 0;处理s是很快的,因为我们可以发现 s [ i ] = s [ i ? 1 ] + a [ i ] ( 公 式 一 ) s[i] = s[i - 1] + a[i](公式一) s[i]=s[i?1]+a[i](公式一)s[i]可以通过循环一遍就得到:
当我们有了s之后,我们想算L到R的和,就可以用s来算了: a [ L ] + a [ L + 1 ] + a [ L + 2 ] + . . . + a [ R ] = s [ R ] ? s [ L ? 1 ] ( 公 式 二 ) a[L] + a[L + 1] + a[L + 2] + ... + a[R] = s[R] - s[L - 1](公式二) a[L]+a[L+1]+a[L+2]+...+a[R]=s[R]?s[L?1](公式二) 可以发现,当我们预处理完一个s之后,我们再去算某一段的和其实非常容易,直接算两个数的差就可以了,也就是我们在每一次算和的时候只用一次运算就可以了,每一次查询都优化了时间复杂度: O ( N ) → O ( 1 ) O(N) → O(1) O(N)→O(1) 二维前缀和我们二维前缀和有没有像一维前缀和那样的公式呢? 在一维中,我们前缀和数组每一个s[i]表示的是原数组前i个数的和; 在二维中,我们前缀和矩阵的这个数就代表着它在原矩阵中左上角所有元素的和: 所有数全部替换为前缀和矩阵: 第一个问题:前缀和矩阵怎么算出来?我们怎么通过原矩阵算出来?
什么是容斥原理呢?看图: 我们的目标是求这六个数的和: 那么我们可以先求这左面四个数的和: 然后再求上面三个数的和: 现在的和是:黄色的格子被算了一次,蓝色的格子被算了两次,所以我们只需要减去所有蓝色的格子,就可以保证我们除了最后一个本身数的格子以外,所有数都只被加了一次,这样我们再加上此数字就可以得到前缀和矩阵的值。 我们总结了一下,前缀和矩阵的值 = 此格子上面所有数的总和 + 此格子左面所有数的总和 - 重复的格子 + 原数 即为: s [ x ] [ y ] = s [ x ? 1 ] [ y ] + s [ x ] [ y ? 1 ] ? s [ x ? 1 ] [ y ? 1 ] + a [ x ] [ y ] ( 公 式 一 ) s[x][y] = s[x - 1][y] + s[x][y - 1] - s[x - 1][y - 1] + a[x][y](公式一) s[x][y]=s[x?1][y]+s[x][y?1]?s[x?1][y?1]+a[x][y](公式一) 我们可以在线性的时间复杂度之内,通过原矩阵算出前缀和矩阵的值,我们只用了常数次计算。 第二个问题:如何利用前缀和矩阵,计算某一个子矩阵的和? 同样: 比方我们想算下图红色子矩阵的和: 但我们现在只知道黄色矩阵的值: 我们需要去掉“倒L”形状的值,这个就可以用容斥原理来去掉,首先去掉左面所有的值,然后再去掉上面的值; 现在,黄色格子我们已经全部去掉了,但是灰色格子我们去掉了两次,所以我们还要再加上它一次。 最终公式:以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为: s [ x 2 , y 2 ] ? s [ x 2 , y 1 ? 1 ] ? s [ x 1 ? 1 , y 2 ] + s [ x 1 ? 1 , y 1 ? 1 ] ( 公 式 二 ) s[x2, y2] - s[x2, y1 - 1] - s[x1 - 1, y2] + s[x1 - 1, y1 - 1] (公式二) s[x2,y2]?s[x2,y1?1]?s[x1?1,y2]+s[x1?1,y1?1](公式二) 我们利用前缀合矩阵以常数次计算快速的求出我们某一个子矩阵的和,时间复杂度优化为: O ( m n ) → O ( 1 ) O(mn) → O(1) O(mn)→O(1) 二维前缀和主要是对一维前缀和的扩展。 容斥原理就是用空间换时间的概念。
例题AcWing 795. 前缀和
暴力的话每一次查询用时 O ( n ) O(n) O(n),一共m次,总共时间复杂度 O ( m n ) O(mn) O(mn) n,m <= 100000 mn = 1e10,超时。 前缀和优化,每一次查询用时 O ( 1 ) O(1) O(1),一共m次,总共 O ( n ) O(n) O(n)。 直接套模板即可。
AcWing 796. 子矩阵的和
输入样例:
输出样例:
第1行的3 4 3,前面两个3 4是矩阵的行列,最后一个3是要查询几次 234行就是矩阵的元素: 第5行的1 1 2 2求的是这个子矩阵的和: 第6行的2 1 3 4求的是这个子矩阵的和: 第7行的1 3 3 4求的是这个子矩阵的和: 也就是说这个题是求一个矩阵的某一个子矩阵的和。 那就直接按照我们前面讲的二维前缀和写代码就ok了,上面已经讲的非常细了。
第八届2017年蓝桥杯真题AcWing 1230. K倍区间
我们看第一个样例: 输入样例:
输出样例:
求5个数某一段连续的区间是2的倍数有多少 长度是1:2,4 2个 长度是2: 0个 长度是3:[1, 3] [3, 5] 2个 长度是4:[1, 4] [2, 5] 2个 长度是5: 0个 总和是6,输出6。 暴力枚举(超时) 最朴素做法
超时,AcWing只过了6/11个数据,蓝桥杯过了2/7个数据,满分100分我只拿到了28分
前缀和优化(超时)
但并没有什么用,AcWing还是超时,蓝桥杯的测评结果跟暴力枚举拿的分一样,我以为能骗到更多的分,这就很懵了
AcWing评测结果 蓝桥杯评测结果 用前缀和干掉了一层循环,但并没有达到我们想要的结果,那我们从哪方面还可以优化呢? 前缀和 + 数学 优化(AC)
我们可以再干掉一层循环。 当 这其实就是我们第二层循环的含义,我们将循环条件简单的变一下: 当 即有多少个 我们可以开一个新的数组,
完整代码 AcWing AC 蓝桥杯满分
因为我们的思路是找到两个序列和 不加 为什么少了两个?因为我们不一定需要两个序列,单个序列取余==0也构成k倍区间,此时我们就要假设 我们 加上 蓝桥杯满分 本题优化: O ( N 3 ) → O ( N 2 ) → O ( N ) O(N^3) → O(N^2) → O(N) O(N3)→O(N2)→O(N)
|
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/26 17:22:07- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |