https://ac.nowcoder.com/acm/problem/20032
题目:
- 一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标。
- 现在地图上有n(N ≤ 10000)个目标,用整数Xi,Yi(其值在[0,5000])表示目标在地图上的位置,每个目标都有一个价值。
- 激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆破范围,即那个边长为R的正方形的边必须和x,y轴平行。
- 若目标位于爆破正方形的边上,该目标将不会被摧毁。(这是可能的干扰项:注意激光炸弹爆破范围的边界不一定要在整数坐标点上。)
思路:
二维前缀和:
f [ i ] [ j ] 表示前 i 行,前 j 列的 val 值之和。容斥原理:
(参考离散数学中集合之间的关系)
要计算对角线从(x1,y1)到(x2,y2)的正方形中(x1<x2,y1<y2) 的所有值之和,结合前缀和,只需要如下操作:
正方形所围成的范围内所有值之和 = f [ x2, y2 ] - f [ x1, y2 ] - f [ x2, y1 ] + f [ x1, y1 ]
其中 f [ x1, y1 ] 为被重复减去后补上的。
下面为两份AC代码;
第一份代码:
#include<stdio.h>
#include<string.h>
const int maxn = 1e4+7;
int pos[maxn][maxn] = {0};
int main () {
int n, r;
scanf("%d %d", &n, &r);
int x, y, val;
int maxx = r, maxy = r;
while (n--) {
scanf("%d %d %d", &x, &y, &val);
pos[x][y] = val;
if (maxx < x) maxx = x;
if (maxy < y) maxy = y;
}
//边界条件——行
for (int j = 1; j <= maxy; j++) {
pos[0][j] += pos[0][j-1];
}
//边界条件——列
for (int i = 1; i <= maxx; i++) {
pos[i][0] += pos[i-1][0];
}
//前缀和初始化
for (int i = 1; i <= maxx; i++) {
for (int j = 1; j <= maxy; j++) {
pos[i][j] += pos[i-1][j] + pos[i][j-1] - pos[i-1][j-1];
}
}
//判断
int max = pos[r-1][r-1];
for (int i = r; i <= maxx; i++) {
for (int j = r; j <= maxy; j++) {
int temp = pos[i][j] - pos[i-r][j] - pos[i][j-r] + pos[i-r][j-r];
if (max < temp) {
max = temp;
}
}
}
//边界条件判断——行
for (int i = r; i <= maxx; i++) {
int temp = pos[i][r-1] - pos[i-r][r-1];
if (max < temp) {
max = temp;
}
}
//边界条件判断——列
for (int j = r; j <= maxy; j++) {
int temp = pos[r-1][j] - pos[r-1][j-r];
if (max < temp) {
max = temp;
}
}
printf("%d", max);
return 0;
}第二份代码:
#include<stdio.h>
#include<string.h>
const int maxn = 1e4+7;
int pos[maxn][maxn] = {0};
int main () {
int n, r;
scanf("%d %d", &n, &r);
int x, y, val;
int maxx = r, maxy = r;
while (n--) {
scanf("%d %d %d", &x, &y, &val);
x++;
y++;
pos[x][y] = val;
if (maxx < x) maxx = x;
if (maxy < y) maxy = y;
}
for (int i = 1; i <= maxx; i++) {
for (int j = 1; j <= maxy; j++) {
pos[i][j] += pos[i-1][j] + pos[i][j-1] - pos[i-1][j-1];
}
}
int max = pos[r][r];
for (int i = r; i <= maxx; i++) {
for (int j = r; j <= maxy; j++) {
int temp = pos[i][j] - pos[i-r][j] - pos[i][j-r] + pos[i-r][j-r];
if (max < temp) {
max = temp;
}
}
}
printf("%d", max);
return 0;
}两份代码的区别:题目的数据坐标是从(0,0)记录的,第一份的二维数组从(0,0)开始存储,第二份的整数数据故意平移一格,从(1,1)开始存储,这样不用单独判断边界条件,更加方便简洁。
第一种方式注意需要考虑边界条件————这很容易漏掉造成代码通过率只有 90% 的情况。

京公网安备 11010502036488号