5001*5001,量太大了,直接用前缀和

整一个5001*5001的二维数组来对应整个地图,数组中的元素表示当前坐标上目标的价值(无目标即为0)

先很普通的用循环记录每个目标的坐标和价值,然后再循环计算前缀和。
计算时,每个点[i][j]上记录的价值和[ i ][ j ]+[ i-1 ][ j ]+[ i ][ j-1 ]-[ i-1 ][ j-1 ] (容斥原理,见下图)
计算前缀和

因为炸弹无法破坏爆炸范围边界上的目标,所以爆炸范围为R的炸弹最多一次可以炸掉R*R个目标(画个图把范围左右移动一下就明白了),我们在计算被破坏的目标的价值和时一样用到容斥原理,[ i ][ j ]-[ i-R ][ j ]-[ i ][ j-R ]+[ i-R ][ j-R ] ,然后记录最大值就可以了

#include<iostream>

using namespace std;
int map[5001][5001] = {0};//二维地图上目标的价值
int main() {
    int n;  //地图上目标的个数
    int R;  //爆破范围正方形的边长
    cin >> n >> R;
    int x, y, v;  //目标的坐标和价值
    int boardX = 0, boardY = 0;
    //输入目标坐标和价值,同时计算前缀和
    for (int i = 0; i < n; ++i) {
        cin >> x >> y >> v;
        map[x][y] = v;
        //记录一下离原点最远的目标的位置,方便提前结束循环缩短运行时间
        if (x > boardX)boardX = x;
        if (y > boardY)boardY = y;
    }
    //计算前缀和
    for (int i = 0; i <= boardX; ++i) {
        for (int j = 0; j <= boardY; ++j) {
            if (i > 0)map[i][j] += map[i - 1][j];
            if (j > 0)map[i][j] += map[i][j - 1];
            if (i > 0 && j > 0)map[i][j] -= map[i - 1][j - 1];
        }
    }
    int maxValue = 0; //一次能炸掉的总价值的最大值
    for (int i = 0; i <= boardX; ++i) {
        for (int j = 0; j <= boardY; ++j) {
            int value = map[i][j];  //这次能炸掉的总价值
            if (i >= R)value -= map[i - R][j];
            if (j >= R)value -= map[i][j - R];
            if (i >= R && j >= R)value += map[i - R][j - R];
            if (value > maxValue)maxValue = value;
        }
    }
    cout << maxValue;
}