二维前缀和:模板+题目
模板:【模板】二维前缀和
题目概述:快速查询二维数组中,某一个子矩阵中所有元素的和
思路:
第一步,预处理二维前缀和矩阵:
f[i][j]表示: 从[1, 1]到[i, j]区域内,所有元素的和
第二步,用二维前缀和解决问题:
#include <iostream>using namespace std;typedef long long LL;
const int N = 1010;
LL f[N][N];
LL a[N][N];LL n, m;
LL q;int main()
{cin >> n >> m >> q;for (int i = 1; i <= n; i++){for (int j = 1; j <= m; j++){cin >> a[i][j];f[i][j] = f[i-1][j] + f[i][j-1] - f[i-1][j-1] + a[i][j];}}while(q--){LL x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2;cout << f[x2][y2]-f[x1-1][y2]-f[x2][y1-1]+f[x1-1][y1-1] << endl;}return 0;
}
题目:P2280 [HNOI2003] 激光炸弹 - 洛谷
思路:暴力枚举出所有边长为m的正方形,找出最大的。
细节问题代码:
- x++, y++; 因为下标从1算起,所以要++
- m = min(m, 5001); 边界问题,如果这个正方形非常非常大,就取5001
- int x1 = x2-m+1; int y1 = y2-m+1; 使用模板的话,x1和y1要 +1
#include <iostream>using namespace std;const int N = 5050;
int a[N][N];
int f[N][N];
int n, m, b;int main()
{cin >> n >> m;while(n--){int x, y; cin >> x >> y >> b;x++, y++; a[x][y] += b;}for (int i = 1; i <= 5010; i++){for (int j = 1; j <= 5010; j++){f[i][j] = f[i-1][j] + f[i][j-1] - f[i-1][j-1] + a[i][j];}}int ret = 0;m = min(m, 5001);for (int x2 = m; x2 <= 5010; x2++){for (int y2 = m; y2 <= 5010; y2++){int x1 = x2-m+1; int y1 = y2-m+1;ret = max(ret, f[x2][y2]-f[x1-1][y2]-f[x2][y1-1]+f[x1-1][y1-1]);}}cout << ret << endl;return 0;
}