前缀和:
先给定义:指某序列的前n项和
是不是与我们高中所学的数列求和类似?
给出用途:
如我们于一组长度为n的整数序列中询问m次,每次询问中输出区间[l,r]中数之和
倘若我们先不使用前缀和,预测一下思路将会是:m次询问中,每一次都求和数组[l,r]
时间复杂度为O(n),思路很简单但若m非常大则将循环很多次,可想而知这并非较优的办法。
回归数列知识,设数列a[n]的前n项和我们设为S[n]
我们要求a[4]到a[10]之和,则可得a[4]+a[10]=S[10]-S[3]即可
所以前缀和便是令S[r]-S[l-1]
接下来便简单了,贴出代码:(于数组a中求区间[l,r]中之和)
#include<iostream> using namespace std; int a[10000],arr[10000];//在main函数的数组默认每一项都为0 int main() { ios::sync_with_stdio, cout.tie(0), cin.tie(0);//这一行是关闭输入输出流的同步,提高程序运行效率,读者可自行去了解 int m,n;//m为询问次数,n为所需序列长度 cin >> m >> n; for (int i = 1; i <= n; ++i) {//i从1开始 cin >> a[i]; arr[i] = arr[i - 1] + a[i]; } while (m--) { int l, r; cin >> l >> r; cout << arr[r] - arr[l - 1] << '\n'; } return 0; }
特别注意:我们这里输入时以i=1为首项,是为了后面i-1时不为-1
前缀和具有良好的查询性质,而差分具有良好的修改性质
差分其实便是前缀和的逆运算,可以快速对数组某一区间进行修改操作
我们需要引入一个辅助数组b[n],令b[i]=a[i]-a[i-1](当i=1时,b[1]=a[1]-a[0],a[0]=0)
以下呈现目的:
我们不妨将b[n]中求和b[1]到b[j]
即b[1]+b[2]+b[3].....+b[j]=(a[1]-a[0]) + (a[2]-a[1]) + (a[3]-a[2]) +....+ (a[j]-a[j-1])
所以则等于a[j],这像不像我们高中时常用的裂项求和?
利用这个如何体现出修改的用途呢?
首先:
a[1]=b[1]
a[2]=b[1]+b[2]
a[3]=b[1]+b[2]+b[3]
a[4]=b[1]+b[2]+b[3]+b[4]
a[n]=b[1]+b[2]+b[3]+b[4]+...+b[n]
假设我们想让[3,n]中的数同时+3
则我们只需令b[3]+3,则a[3]往后数的都会同时+3
如:
a[3]+3=b[1]+b[2]+b[3]+3
a[4]+3=b[1]+b[2]+ (b[3]+3) +b[4]
...
那如果只令一小段,如[3,5]中同时+3呢
我们只需令b[3]+3,再让b[6]-3
我们于草稿纸中画出
不难发现a[3]往后同时+3,再让a[6]往后同时-3,则只有a[3]到a[5]进行了+3的修改
这种方法是否比通过循环令原数组挨个修改快速许多?
解决问题:给定一个长度为
标签:arr,数组,int,cout,cin,差分,一维,前缀 From: https://www.cnblogs.com/Mashiro-zBlog/p/18263720