【模版】前缀和
问题引入:
【洛谷P8218】
## 题目描述
给定 个正整数组成的数列 和 个区间 ,分别求这 个区间的区间和。
对于所有测试数据,
最朴素的想法,就是对于每次询问,我们都用for循环进行 区间的求和,不难看出时间复杂度为O(n*m)。
而如果我们利用前缀和,便可以把时间复杂度优化成O(m+n)。
所以前缀和是一种预处理,用于降低查询时的时间复杂度。
一维前缀和的定义:
设si为数列a从第一个数到第i个数的和,当i>=1时,显然有s[i]=s[i-1]+a[i],这里s[i]数组记录的数值称为前缀和。
若要求出区间的和,只需要求s[r]-s[l-1],单次时间复杂度为O(1)
本题AC代码如下:
#include<iostream>
using namespace std;
#define MAXN 100010;
int n,m;
int a[MAXN],s[MAXN];
int main() {
cin >> n;
for (int i=1;i<=n;i++) {
cin >> a[i]; //若要使用前缀和,数组最好从下标1开始
s[i]=s[i-1]+a[i];
}
cin >> m;
for (int i=1,l,r;i<=m;i++) {
cin >> l >> r;
cout << s[r]-s[l-1];
}
return 0
}
二维前缀和的定义:
我们讲一下什么是二维前缀和,建立在一维前缀和之上,我们要求一个矩阵内一个任意的子矩阵的数的和,我们就可以用二维前缀和。
设s[i,j]表示以(1,1)为矩阵左上角端点,(i,j)为左下角端点矩阵的和。首先计算s[i,j-1]和s[i-1,j]的和,红色区域被算了两遍,所以减去一个s[i-1,j-1]最后加上a[i,j]的值,就可以得到s[i,j]
递推式为:
s[i,j]=s[i-1,j]+s[i,j-1]-s[i-1,j-1]+a[i,j]
若需要快速求出以(x1,y1)为左上角端点,(x2,y2)为右下角端点的矩阵内元素的和
递推式为:
a[i,j]=s[x2,y2]-s[x2,y1-1]-s[x1-1,y2]+s[x1-1,y1-1]
实现代码:
#include<iostream>
#include<cstring>
using namespace std;
int dp[2000][2000],map[2000][2000];
int main()
{
int m,n,k;//所给的矩阵是n*m的,有k组查询
cin >>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin >>map[i][j];
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)//预处理一波
for(int j=1;j<=m;j++)
dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+map[i][j];
for(int i=1;i<=k;i++)//接受查询
{
int x1,x2,y1,y2;
cin >>x1>>y1>>x2>>y2;
cout <<(dp[x2][y2]+dp[x1-1][y1-1]-dp[x1-1][y2]-dp[x2][y1-1])<<endl;//O(1)查询
}
return 0;
}
差分数组自己求前缀和
for (int i=1;i<=n;i++,)
for (int j=1;j<=n;j++)
a[i][j] += a[i-1][j] + a[i][j-1] - a[i-1][j-1];
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!