题目:激光炸弹                          考察内容:二维前缀和                              题目链接:99. 激光炸弹 - AcWing题库

思路:


上面推导的公式从左上(1,1)一直到右下(i,j)推导出的结论," src="https://uploadfiles.nowcoder.com/images/20220815/318889480_1660553763718/D9FDAE9918A39C99254A9D8D179628E5" />若放入一个坐标中需要沿x轴投影,即从左下的(1,1)遍历到右上的(i,j),而递推式中A[i][j] 为该坐标系中右上的点:即代码从(r,r)开始遍历直到遍历完所有坐标系中所有的点
#include <bits/stdc++.h>
#define ios                               \
    ios::sync_with_stdio(false); \
    cin.tie(nullptr);                     \
    cout.tie(nullptr)
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
#define lowbit(x)  ((x) & - (x))
#define pb push_back
#define SZ(v) ((int)v.size())
#define PI acos(-1)
#define x first
#define y second
#define mem(a,b) memset((a),(b),sizeof(a))
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f; 
const ll LLINF=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-6;
const int MAX=2e5+10;
const ll mod=1e9+7;
/********************************* std-head *********************************/
								   
using namespace std;
const int N = 5e3 + 10; //不能开 1e5+10, 内存限制比较严格

int s[N][N];
int n, r;

int main() {
    ios;
    cin >> n >> r;
    r = min(5001, r); // 因为r最大可以取 10^9
    for (int i = 0; i < n; i++) {
        int x, y, w;
        cin >> x >> y >> w;
//        s[++x][++y]=w;  //错误
        s[++x][++y] += w; //右移一位, 就不需要考虑边界了, 并且必须是+=, 不能是=, 因为1个位置可能有多个目标
    }
    for (int i = 1; i <= 5001; i++) {
        for (int j = 1; j <= 5001; j++) {
//            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + s[i][j](a[i][j]);
            s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];   //求出坐标系中每个点相对于(1,1)的二维前缀和 
        }
    }
    int ans = 0;
    for (int i = r; i <= 5001; i++) {
        for (int j = r; j <= 5001; j++) {
            ans = max(ans, s[i][j] - s[i - r][j] - s[i][j - r] + s[i - r][j - r]);//获得点(i,j)在正方形边长为R的区域的前缀和 
        }
    }
    cout << ans << endl;
    return 0;
}