算法笔记之前缀和
一维前缀和
先看一道例题:
例题
题目描述
给定 \(n\) 个正整数组成的数列 \(a_1, a_2, \cdots, a_n\) 和 \(m\) 个区间 \([l_i,r_i]\),分别求这 \(m\) 个区间的区间和。
样例输入
4
4 3 2 1
2
1 4
2 3
样例输出
10
5
提示
样例解释:第 1 到第 4 个数加起来和为 10。第 2 个数到第 3 个数加起来和为 5。
- 对于 \(100\%\) 的数据:\(1 \leq n,m\le 10^5\),\(1 \leq a_i\le 10^4\)。
暴力?
梦想是美好的,但OI生涯是残酷的
很明显只能拿部分分
前缀和
这时候终于请到了我们的主角——前缀和
定义
前缀和(Prefix Sum):对于一个给定的数列 \(a\), 它的前缀和数列 \(sum\) 是通过递推能求出来得 $sum_i=\sum_{j=1}^{i} $ 部分和。
也就是指某一序列的前 \(n\) 项和。
感性理解
其实前缀和的意思就是对于给定的数组 \(a\),他的前 \(i\) 项和 \(sum_i\) 就表示数组中 \(a_0-a_i\) 的和,具体为:
\(sum_0=a_0\)
\(sum_1=a_0+a_1\)
\(sum_2=a_0+a_1+a_2\)
……
\(sum_i=a_0+a_1+...+a_i\)
一维前缀和就是基于一维数组的前缀和
询问区间为 \([1\),\(4]\)
那么就是求 \(1\) 到 \(4\) 的和
按照暴力的思路,我们需要从 \(1\) 到 \(4\) 遍历一遍求和
其实我们可以在询问前离线求出前缀和 \(sum\) 数组,而询问的区间就是 \(sum_4\) 的值,完全可以 \(O(1)\) 得到答案
但区间还有可能不是从 \(1\) 开始的
首先得到前缀和数组 \(sum=[4,7,9,10]\)
其实要求的区间 \([2\),\(3]\),就是用区间 \([1\),\(3]\) 的和减去区间 \([1\),\(1]\) 的和
即询问的区间和为 \(sum_r-sum_{l-1}\)
这样我们就可以在询问过程中用 \(O(1)\) 解决这个问题
实现
首先是预处理出前缀和数组
根据之前的解释,我们可以求出 \(sum\) 数组:
for(int i=1;i<=n;i++)
{
cin>>a[i];
for(int j=1;j<=i;j++)
cin>>sum[i];
}
但这种方法的复杂度太高了,我们需要更好的方法来求前缀和
通过观察最上面的算式,我们不难发现:
\(sum_i=sum_{i-1}+a_i\)
因此可以用 \(O(1)\) 解决这个问题
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=sum[i-1]+a[i];
}
接下来处理询问
在上面已经解决了快速求出区间和的方法,可以直接解决
while(m--)
{
int l,r;
cin>>l>>r;
cout<<sum[r]-sum[l-1]<<endl;
}
接下来是完整的一维前缀和代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+1;
int n,m;
int a[N],sum[N];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=sum[i-1]+a[i];
}
cin>>m;
while(m--)
{
int l,r;
cin>>l>>r;
cout<<sum[r]-sum[l-1]<<endl;
}
return 0;
}
二维前缀和
例题
题目描述
给一个 \(n\times n\) 矩阵。要求矩阵中最大加权矩形,即矩阵的每一个元素都有一权值,权值定义在整数集上。从中找一矩形,矩形大小无限制,是其中包含的所有元素的和最大 。矩阵的每个元素属于 \([-127,127]\) ,例如
0 –2 –7 0
9 2 –6 2
-4 1 –4 1
-1 8 0 –2
在左下角:
9 2
-4 1
-1 8
和为 \(15\)。
请你计算出所给的矩形中加权和最大的矩形。
输入格式
第一行:\(n\),接下来是 \(n\) 行 \(n\) 列的矩阵。
输出格式
最大矩形(子矩阵)的和。
样例输入
4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
样例输出
15
提示
\(1 \leq n\leq 120\)
$$这个人颓废去了,n年后再更$$
本文来自博客园,作者:FHenryh,转载请注明原文链接:https://www.cnblogs.com/FHenryh/p/Prefix_Sum.html

浙公网安备 33010602011771号