一维&二维前缀和
基础知识:
一维前缀和:
S[ i ] = a[ 1 ] + a[ 2 ] + ... a[ i ]
a[ l ] + ... + a[ r ] = S[ r ] - S[l - 1]
二维前缀和:
S[i, j] = 第 i 行 j 列格子左上部分所有元素的和
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]
1. 激光炸弹
题目链接:https://www.acwing.com/problem/content/101/ (算法竞赛进阶指南)
思路:1. 先求出每一个以(i, j)为右下角节点,(0, 0) 为左上角节点的矩形的二维前缀和
2. 枚举每一个R * R的矩阵,求出最大值
代码:
#include <algorithm> #include <cstring> #include <iostream> using namespace std; #define N (int)5e3 + 10 int n, m; int s[N][N]; int main(void) { int cnt, R; scanf("%d%d", &cnt, &R); R = min(R, 5001); n = m = R; //扩展到和R一样大 while(cnt--) { int x, y, w; scanf("%d%d%d", &x, &y, &w); n=max(n,++x),m=max(m,++y); s[x][y] += w; //不同目标可能在同一位置 } for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1]; int res = 0; // 枚举所有边长是R的矩形, 枚举(i,j) 为右下角 for(int i = R; i <= n; i++) for(int j = R; j <= m; j++) res = max(res, s[i][j] - s[i - R][j] - s[i][j - R] + s[i - R][j - R]); printf("%d\n", res); return 0; }

浙公网安备 33010602011771号