##[$AcWing$ $99$. 激光炸弹](https://www.acwing.com/problem/content/description/101/) ### 一、题目描述 地图上有 $N$ 个目标,用整数 $X_i,Y_i$ 表示目标在地图上的位置,每个目标都有一个价值 $W_i$。 **注意**:不同目标可能在同一位置。 现在有一种新型的激光炸弹,可以摧毁一个包含 $R×R$ 个位置的正方形内的所有目标。 激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆炸范围,即那个正方形的边必须和 $x,y$ 轴平行。 求一颗炸弹 **最多** 能炸掉地图上 **总价值为多少** 的目标。 **输入格式** 第一行输入正整数 $N$ 和 $R$,分别代表地图上的目标数目和正方形包含的横纵位置数量,数据用空格隔开。 接下来 $N$ 行,每行输入一组数据,每组数据包括三个整数 $X_i,Y_i,W_i$,分别代表目标的 $x$ 坐标,$y$ 坐标和价值,数据用空格隔开。 **输出格式** 输出一个正整数,代表一颗炸弹最多能炸掉地图上目标的总价值数目。 **数据范围** $0≤R≤10^9$ $0包着 某个坐标才行! **解决办法:整体偏移$0.5$** #### $4$、注意数据范围 炸弹的范围会超过$5000$,而且如果是范围是$0$直接返回$0$ ### 四、实现代码 ```cpp {.line-numbers} #include using namespace std; const int N = 5010, M = 5001; // 前缀和数组 int s[N][N]; int main() { // n:点的数量,R:边长 int n, R; cin >> n >> R; // 这里本题数据有些坑,R有时输入会比我们整个矩阵大,所以这里设置输入的R过大,就直接取M R = min(R, M); // R太大,对于我们来说没有意义,因为它>5001时,就把所有位置全部摧毁掉~ for (int i = 1; i <= n; i++) { int x, y, w; cin >> x >> y >> w; // 因为每题的(x,y)是默认下标从0开始,与前缀和的习惯不太相符,所以,这里直接将原坐标x+1,y+1,映射到下标从(1,1)开始 x++, y++; // 0≤Xi,Yi≤5000 s[x][y] += w; // 不同目标可能在同一位置,s数组同时也充当了a数组 } // 二维前缀和公式 for (int i = 1; i <= M; i++) for (int j = 1; j <= M; j++) s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1]; // 枚举所有边长为R的正方形,取最大值就OK了(枚举的是右下角) => (R-1)*(R-1)的矩阵 int res = 0; for (int i = R; i <= M; 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; } ```