前缀和与差分(类似于数列求和,求通项)

本文介绍了一维和二维的前缀和算法及其应用场景,包括如何通过前缀和快速查询区间和,以及一维和二维差分算法的实现方法,用于高效地更新区间内的数值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

优点:查询区间和时可以将O(n)降到O(1)

一维前缀和 —— 模板题 AcWing 795. 前缀和
S[i] = a[1] + a[2] + ... a[i]
a[l] + ... + a[r] = S[r] - S[l - 1]
二维前缀和 —— 模板题 AcWing 796. 子矩阵的和
S[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]
一维差分 —— 模板题 AcWing 797. 差分
给区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c
二维差分 —— 模板题 AcWing 798. 差分矩阵
给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:
S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c

### C++ 中前缀和差分算法实现 #### 前缀和的概念及其构建方法 前缀和是指某个序列的前 n ,这可以被理解为数学中的数列前 n 过合理利用前缀和技术能够简化一些复杂的计算问题[^1]。 对于给定的一个整型数组 `a` ,可以过如下方式来创建其对应的前缀和数组 `s` : ```cpp vector<int> buildPrefixSum(const vector<int>& a) { int n = a.size(); vector<int> s(n); // 初始化第一个元素 if (n > 0) s[0] = a[0]; // 构建其余部分 for (int i = 1; i < n; ++i) { s[i] = s[i - 1] + a[i]; } return s; } ``` 此函数接收一个输入向量并返回一个新的表示累积总的结果向量。注意这里假设索引是从零开始计数的[^4]。 #### 使用前缀和优化区间查询操作 当需要频繁执行区间的求和时,预先计算好前缀和能极大提高效率。比如要获取 `[l, r]` 范围内的元素累加值: ```cpp // 计算闭合区间[l,r]内所有元素的 int queryRangeSum(int l, int r, const vector<int>& prefix_sum) { if(l == 0){ return prefix_sum[r]; }else{ return prefix_sum[r] - prefix_sum[l-1]; } } ``` 这段代码展示了如何基于已经准备好的前缀和数据结构快速完成任意指定范围内的数值汇总工作[^2]。 #### 差分概念及其实现 差分是用来处理连续区域内统一增减的情况的有效工具之一。具体来说就是在原数组基础上建立一个辅助性的差异数组,在这个新的数组里记录下每次变化的影响程度;之后再过对这些影响做累计叠加从而恢复出修改后的实际状态[^3]。 下面是一个简单的例子说明怎样用差分技术更新特定范围内所有的值: ```cpp void applyDifference(vector<int>& diff, int start, int end, int value) { // 对[start,end]之间的每一个位置都增加了value diff[start] += value; // 如果end不是最后一个元素,则在end+1处抵消掉这次增量效果 if(end + 1 < diff.size()){ diff[end + 1] -= value; } } // 应用差分后重建原始数组 vector<int> reconstructFromDiff(const vector<int>& original_diff) { int n = original_diff.size(); vector<int> result(n); result[0] = original_diff[0]; for(int i=1;i<n;++i){ result[i] = result[i-1]+original_diff[i]; } return result; } ``` 上述两个函数共同作用实现了对某一固定长度片段施加相同改变的操作,并且能够在O(N)时间内高效地还原最终形态下的整个列表。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值