嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的passion。准备好和我一起冲进代码的奇幻宇宙了吗?Let's go!
我的博客:yuanManGan
目录
前缀和
解决某种算法呢一般要从题目入手,我们针对一类题目有一类的算法,不会凭空出现一类算法,而我们的前缀和算法就以这道题为插入吧:
⼀维前缀和
题目理解:
题目很简单就给一个数组,再给一个区间,求区间类的数的和。
思路讲解:
暴力解法:
很多人上来的第一思路就和我一样(没学习前缀和之前),求一次区间就累加一次呗,但我们注意这里的数据范围,如果这样实现的话,时间复杂度就成了n*q(1e5*1e5)显然会超时。这时我们就提出我们本文要学习的前缀和算法了
前缀和:
我们可以对这个数组进行预处理,算出每个下标的前面的数累加的结果,比如:
就是创建一个数组来有预处理原数组,从而创建一个前缀和数组,当要求某一段区间时,比如求2~4区间的和时我们仅需要,使用前缀和数组的4下标减去1下标的数,求x~y区间,也就是求前缀和数组中的y下标减去x-1下标即可
代码实现
由于第一种做法太简单大家自己实现即可
前缀和:
#include<iostream>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int n, q;
//不需要创建原数组
//LL a[N];
//前缀和数组
LL f[N];
int main()
{
cin >> n >> q;
//预处理
for (int i = 1; i <= n; i++)//下标从1开始避免边界情况
{
int x; cin >> x;
f[i] = f[i - 1] + x;
}
//q次询问
while (q--)
{
int x, y; cin >> x >> y;
cout << f[y] - f[x - 1] << endl;
}
return 0;
}
有了一维前缀和的铺垫,我们就可以讲解二维前缀和问题了:
⼆维前缀和
二维前缀和,和一维前缀和思路是一样的但实现方法不同,二维前缀和需要使用二维数组来进行预处理。

题目理解:
给个二维数组,求两个坐标(一个为左上角,一个为右下角)组成的长方形的所有点的和。
思路讲解:
暴力解法:
两次for循环,直接加,时间复杂度依旧为nq(1e4*1e5)会出现超时的。
二维前缀和:
我们定义一个二维数组f [ ] [ ]来预处理a[ ] [ ]数组中的元素,
f[x] [y] = f[x - 1] [y - 1] + f[x] [y - 1] + f[x - 1] [y] - a[x] [y];
这样就可以对原数组进行预处理。
那我们怎么得到所求的答案呢?看图
A = (A + B + C + D) - (B + C) - (C - D) + C
答案 == f (x2) (y2) - f (x2)(y1 - 1) - f(x1 - 1)(y2) + f(x1- 1)( y1 - 1);
这里要注意我们是以x1y1为左上角,所以这里涉及到x1y1的地方都进行的减一操作。
代码实现:
#include<iostream>
using namespace std;
typedef long long LL;
const int N = 1e3 + 10;
//前缀和数组
LL f[N][N];
int n, m, q;
int main()
{
cin >> n >> m >> q;
//预处理操作
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
int x; cin >> x;
f[i][j] = x + f[i][j - 1] + f[i - 1][j] - f[i - 1][j - 1];
}
}
//q次操作
while (q--)
{
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
cout << f[x2][y2] - f[x2][y1 - 1] - f[x1 - 1][y2] + f[x1 - 1][y1 - 1] << endl;
}
}
上述分享的仅为一般模板,题目还是要根据不同题目不同程度地修改模板。
题目试手
一维前缀和:
二维前缀和:
我的答案贴在最后了
最大字段和:
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
//前缀和数组
LL f[N];
int n;
int main()
{
cin >> n;
//预处理
for (int i = 1; i <= n; i++)
{
int x; cin >> x;
f[i] = f[i - 1] + x;
}
LL ret = -1e20;
LL prevmin = 0;
for (int i = 1; i <= n; i++)
{
ret = max(ret, f[i] - prevmin);
prevmin = min(prevmin, f[i]);
}
return 0;
}
激光炸弹:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
const int N = 5e3 + 10;
int f[N][N];
int a[N][N];
int n, m;
int main()
{
cin >> n >> m;
while (n--)
{
int x, y, v; cin >> x >> y >> v;
a[++x][++y] += v;
}
n = 5009;
for (int i = 1; i <= n;i ++)
for (int j = 1; j <= n; j++)
f[i][j] = a[i][j] + f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1];
int ret = 0;
m = min(m, n);
for (int x2 = m; x2 <= n; x2++)
{
for (int y2 = m; y2 <= n; y2++)
{
int x1 = x2 - m + 1, y1 = y2 - m + 1;
int sum = f[x2][y2] - f[x1 - 1][y2] - f[x2][y1 - 1] + f[x1 - 1][y1 - 1];
ret = max(sum, ret);
}
}
cout << ret << endl;
return 0;
}