前缀和目录
一维前缀和
给定一个序列,定义pre[i]=pre[i−1]+a[i]
可求区间[l,r]的和:pre[r]−pre[l−1]
牛客例题:校门外的树
题解代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <string>
#define IC ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
int a[11000];
int main(){
IC;
int l,m;
int x,y;
cin >> l >> m;
for(int i = 1; i <= m; i++){
cin >> x >> y;
a[x] -=1;
a[y+1] +=1;
}
int ans = 0;
for(int i = 0; i <= l; i++){
a[i]+=a[i-1];
if(!a[i])ans++;
}
cout << ans << endl;
return 0;
}
二维前缀和
公式: pre[i][j]=pre[i−1][j]+pre[i][j−1]−pre[i−1][j−1]+a[i][j],pre[i][j]
假设在这个矩阵(二维数组)中,我们要求和的是上图中红区。现在我们已经预处理出了所有点的前缀和,现在给定两个点(x1,y1),(x2,y2) 我们要求 以这两个点连线为对角线的一个子矩阵的数值之和。
首先我们可以把s[x2][y2]求出来,它代表整个大矩形的前缀和,然后我们分别减去它左边多出来的一块的前缀和和下边多出来一块的前缀和。
最后可以发现绿色部分多剪了一次,加回来,就ok了。
所以对于一次的查询答案ans应该等于s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]
牛客例题:激光炸弹
题解代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <string>
#define IC ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int Max = 5010;
int g[Max][Max];
int main() {
IC;int N, R;
cin >> N >> R;
int xx = R, yy = R;//xx和yy表示边界,初始化为最小的R
for (int i = 0,x,y,w; i < N; ++i) {
cin >> x >> y >> w;
x++; y++;//坐标x,y都要加1,因为这道题目的坐标是从0开始的
g[x][y] = w;
xx = max(xx, x);
yy = max(yy, y);
}
for (int i = 1; i <= xx; i++)
for (int j = 1; j <= yy; j++)
g[i][j] = g[i - 1][j] + g[i][j - 1] - g[i - 1][j - 1] + g[i][j];//求前缀和
int ans = 0;
for (int i = R; i <= xx; i++) {
for (int j = R; j <= yy; j++) {
ans = max(ans, g[i][j] - g[i - R][j] - g[i][j - R] + g[i - R][j - R]);//用提前算好的前缀和减去其他部分再补上多剪的那部分
}
}
printf("%d\n", ans);
return 0;
}
三 重要 重要 重要
重要的事情说三遍
爱你爱你爱你
点赞点赞点赞