一.前缀和
为什么需要前缀和,假设你现在让你计算在任意区间【l,r】m次
暴力做法:
时间复杂度o(m*n)
那现在我们就来介绍前缀和
1.原理和特点
presum表示前缀和,前缀和由一个用户输入的数组生成。
用一个presum数组预处理记录每一段a数组的值
对于一个数组a[](下标从1开始),定义一个前缀和数组presum[],满足:
presum有一个重要特征,可用于快速生成presum:
2.求区间和
presum可以o(1)的求某一段区间和:
sum[l,r]=presum[r]-presum[l-1]
3.适用范围
presum只适合a为静态数组的情况下,即a数组元素在查询过程中不会进行修改
4.实现
4.1前缀和数组实现
for (int i = 1; i <= n; i++)
{
presum[i] = presum[i - 1] + a[i];//尽量把a[]和presum[]写为全局变量 因为前缀和默认a[0]和presum[0]为0
}
4.2区间和实现
可以明显看到时间复杂度变为O(m+n)
二.例题
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
char s[N];
int presum[N];
int main()
{
cin>>s+1;//前缀和从s[1]开始
int n=strlen(s+1);//长度从1开始计算
for(int i=1;i<=n;i++)
presum[i]=presum[i-1]+(s[i]=='L'?1:-1);//笔记第一步
int maxcount=0;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
if(presum[j]-presum[i-1]==0) maxcount=max(maxcount,j-i+1);//笔记第二步
cout<<maxcount;
}
三.差分
有一个原数组a,通过两两做差,构造一个新数组diff。
所以只要有diff数组,通过前缀和叠加,就可以得到a数组。
3.1差分的好处
在给定区间[l,r],让我们把a数组中的【x,y】中都加上c,那我们应该如何做
3.11暴力做法
用for循环在x到y之间,全部遍历加上c,但如果要操作m次,那时间复杂度就是o(n*m).
3.12差分做法
首先用for循环得到差分数组
之后将diff[x]加上c,这样会使得整个a数组全部加上c,如图
如果diff[x]变为diff[x]+c,由于a数组是diff数组进行前缀和,所以每一个a数组元素都会+c
由于之后我们只需要在x到y之间+c,但一个diff+c会导致整个数组都+c,所以我们需要在diff[y+1]-c,就能抵消掉。
之后将diff数组进行前缀和就能得到数组a。
时间复杂度:o(m+n)比暴力o(m*n)更加快速