Basic Thought / Data Structure: 前缀和 Prefix Sum

在OI中,前缀和是一个重要的优化思想

Function: 求静态区间和

模板题:输入序列\(a_{1..n}\),对于每一个输入的二元组\((l,r)\),求\(\sum_{i=l}^ra_i\)

先想一想朴素算法怎么做吧

对于输入的每一组\((l,r)\),遍历序列\(a_{l..r}\)求和,代码如下

int s(0);
for(int i(l);i<=r;++i)s+=a[i];
return s;

Time complexity: \(O(n)\)

Memory complexity: \(O(1)\)

如果有m次询问,则总时间复杂度\(O(nm)\)

观察这个过程,可以发现有大量多余运算,比如说,对于两次询问,它们区间的交集就是被多余运算的

那么有没有方法使得计算量减少呢?

可以发现\(\sum_{i=l}^ra_i=\sum_{i=1}^ra_i-\sum_{i=1}^{l-1}a_i\)

也就是说如果存在数组\(s_{1..n}\)使得\(s_i=\sum_{j=1}^ia_j\),则

\(\sum_{i=l}^ra_i=s_r-s_{l-1}\)

\(s_{1..n}\)就是传说中的前缀和数组啦!

Operation:

  First: 将普通数组\(a_{1..n}\)构造成前缀和数组\(s_{1..n}\)

  Second: 对于输入区间\([l,r]\),直接计算出区间和\(s_r-s_{l-1}\)

关键就是前缀和数组如何构造

使用递推思想

\(s_i=\sum_{j-1}^ia_j=\sum_{j-1}^{i-1}a_j+a_i=s_{i-1}+a_i\)

代码如下

\(s_{1..n}\)

for(int i(1);i<=n;++i)s[i]=s[i-1]+a[i];

询问

return s[r]-s[l-1];

到此为止前缀和的所有基本操作都讲完啦!

Conclusion & Extension:

前缀和是一种泛用性很高的数据结构,也是非常重要的优化思想

它利用预处理和递推的方法减少多余运算,达到优化的目的,被广泛运用于dp的优化中

不仅适用于加法,还适用于所有满足于结合律而且具有单位(对于加法就是0)和逆元(a的逆元是-a)的二元运算,如乘法

但是对于求最值就不太靠谱了(对于这类问题(称为RMQ问题)也有很棒的算法)

前缀和思想的强大产物:树状数组

Particularly, 前缀和还有逆运算,叫差分

到此为止本篇文章就圆满结束啦,请各位奆佬们多多指教和支持,THX!

猜你喜欢

转载自www.cnblogs.com/BrianPeng/p/12165425.html