《算法竞赛进阶指南》[HNOI2003]激光炸弹--题解

A-[HNOI2003]激光炸弹_0x03 基本算法-递归

https://ac.nowcoder.com/acm/contest/999/A

题目描述
一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标。
现在地图上有n(N ≤ 10000)个目标,用整数Xi,Yi(其值在[0,5000])表示目标在地图上的位置,每个目标都有一个价值。
激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆破范围,即那个边长为R的正方形的边必须和x,y轴平行。
若目标位于爆破正方形的边上,该目标将不会被摧毁。

输入描述:
输入文件的第一行为正整数n和正整数R,接下来的n行每行有3个正整数,分别表示 xi,yi ,vi 。

输出描述:
输出文件仅有一个正整数,表示一颗炸弹最多能炸掉地图上总价值为多少的目标(结果不会超过32767)。


前缀和
其实可以把它理解为数学上的数列的前n项和(对于一个一维数组的前缀和)。
我们定义对于一个数组a的前缀和数组s,s[i] = a[1]+a[2]+...+a[i].

二维前缀和
与一维前缀和类似,设s[i][j]表示所有a[i'][j']的和。(1≤i'≤i,1≤j'≤j)
有一点像“矩形的面积”那样,把一整块区域的值都加起来。

当给出一个数列s,要求你回答m次询问,每次询问下标j到k(k > j)的和。怎么算更快呢?暴力发就是每次询问都执行一次相加操作,然后输出结果。
可是这样算会TLE的。可以先提前算好每一次的前缀和,再用s[k]-s[j],这样便会使计算量大大减小。

图片说明
(图片来源于网络)

假设在这个矩阵(二维数组)中,我们要求和的是上图中红区。现在我们已经预处理出了所有点的前缀和,现在给定两个点(x1,y1),(x2,y2),我们要求 以这两个点连线为对角线的一个子矩阵的数值之和。

首先我们可以把s[x2][y2]求出来,它代表整个大矩形的前缀和,然后我们分别减去它左边多出来的一块的前缀和和下边多出来一块的前缀和。
最后可以发现绿色部分多剪了一次,加回来,就ok了。
所以对于一次的查询答案ans应该等于

废话少说直接上代码:

完整C++版AC代码

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;

const int N = 5010;//这个N表示点最多的数量
int g[N][N];

int main() {

    int N, R;//为了方便就重名了,两个N重名是没关系的,因为会优先选择函数里的
    cin >> N >> R;
    int xx = R, yy = R;//xx和yy表示边界,初始化为最小的R

    for (int i = 0,x,y,w; i < N; ++i) {
        cin >> x >> y >> w;
        x++; y++;//坐标x,y都要加1,因为这道题目的坐标是从0开始的
        g[x][y] = w;
        xx = max(xx, x);
        yy = max(yy, y);
    }

    for (int i = 1; i <= xx; i++) 
        for (int j = 1; j <= yy; j++)
            g[i][j] = g[i - 1][j] + g[i][j - 1] - g[i - 1][j - 1] + g[i][j];//求前缀和

    int ans = 0;
    for (int i = R; i <= xx; i++) {
        for (int j = R; j <= yy; j++) {
            ans = max(ans, g[i][j] - g[i - R][j] - g[i][j - R] + g[i - R][j - R]);//用提前算好的前缀和减去其他部分再补上多剪的那部分
        }
    }
    printf("%d\n", ans);
    return 0;
}
全部评论
他把坐标轴原点从(0,0)变成(1,1),但算边界的时候是从R开始,而不是R+1,这点保证了正方形边缘不算
2 回复 分享
发布于 2020-07-02 10:19
想请问下正方形边缘不算是怎么体现的?
2 回复 分享
发布于 2020-01-29 13:59
这个边缘不能算也有太有点歧义了,直接就说正方形括起来的都算不就行了嘛
点赞 回复 分享
发布于 2023-11-07 11:50 湖南
博主,为什么这里的x1和y1 都需要-1啊 s[x2][y2]−s[x2][y1−1]−s[x1−1][y2]+s[x1−1][y1−1] 。
点赞 回复 分享
发布于 2020-07-03 10:01

相关推荐

05-07 13:29
已编辑
门头沟学院 Java
北斗导航Compass低仿版:能不能先搞清楚优先级啊,怎么可能是项目问题,项目很重要吗?又没学历 又没实习大厂凭啥约面?那玩具项目 没应用在真实生产环境下的 就算做上天又有什么用?早点找个小公司实习 拿小公司实习去投大厂实习,这才是你现在该做的
投递美团等公司9个岗位 简历被挂麻了,求建议
点赞 评论 收藏
分享
评论
34
2
分享

创作者周榜

更多
牛客网
牛客企业服务