题目
思路
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;
}