- 前缀和
前缀和顾名思义就是前面i个数的总和。
假设有一个序列A,前缀和为S。根据概念很容易知到公式
\(S[i]=\displaystyle \sum_{j=1}^iA[j]\)如何求区间\([l,r]\)的和呢?
\(sum[l,r]=s[r]-s[l-1]\)那如果要对多个不同区间
\([l,r]\)进行加减操作呢?然后输出某个区间\([l,r]\)的区间和,接下来就要用到差分数组了
- 差分数组
设原数组为\(A[i]\),差分数组为\(B[i]\),则:
\[B[i]=\begin{cases} A[i]&i=1\\ A[i]-A[i-1]&i\geq2 \end{cases}\]
差分数组的性质:
- 如果对区间\([l,r]\)进行修改,只需修改\(B[l],B[r+1]\)(\(B[l]\)加上修改值,\(B[r+1]\)减去修改值)
- \(A[i]=\displaystyle \sum_{j=1}^{i}B[j]\)(通过\(B[i]=A[i]-A[i-1]\)证明)
- $S[x]=\displaystyle \sum_{i=1}^{x}A[i]=\displaystyle \sum_{i=1}^{x} \displaystyle \sum_{j=1}^{i}B[j]=\displaystyle \sum _{i=1}^{x}(x-i+1)*B[i] $
有n个数。m个操作,每一次操作,将x~y区间的所有数增加z;
最后有q个询问,每一次询问求出x~y的区间和。
设原数组为\(A[i]\)
步骤:
- 先求出差分数组\(B[i]=A[i]-A[i-1]\)
- 在根据\(m\)个造作修改\(B[i]\)
- 求修改后的\(A[i]=A[i-1]+B[i]\)
- 求前缀和\(S[i]=S[i-1]+A[i]\)
- 最后输出区间和\(sum[x,y]=S[y]-S[x-1]\)
举个栗子 航班预订统计
这道题很简单,没有要求输出区间和,也不用先求出差分数组
#include<iostream>
using namespace std;
int n; //n个航班
int i; //i条预定记录
int b[20005]; //差分数组
int main()
{
cin>>n>>i;
for(int j=0;j<i;j++)
{
int x,y,z; //[x,y]预定了z个座位
cin>>x>>y>>z;
b[x]+=z;
b[y+1]-=z;
}
for(int k=1;k<=n;k++)
{
b[i]+=b[i-1];
cout<<b[i]<<' ';
}
}
前面都是一维前缀和,再举个一位前缀和的栗子 最大子矩阵
没有涉及区间修改,只是求前缀和
#include<iostream>
#include<algorithm>
using namespace std;
int m,n; //整数矩阵
int x,y; //所求子矩阵的长和宽
int b[1000][1000];
int ans;
int main()
{
cin>>m>>n>>x>>y;
int t;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
{
cin>>t;
b[i][j]+=b[i-1][j]+b[i][j-1]+b[i-1][j-1]+t;
if(i>=x&&j>=y)
ans=max(ans,b[i][j]-b[i-x][j]-b[i][j-y]-b[i-x][j-y]);
}
cout<<ans<<endl;
}
原文地址:https://www.cnblogs.com/mrpeng2333/p/11183654.html
时间: 2024-10-17 11:15:51