激光炸弹

激光炸弹

题目描述

在这里插入图片描述


题意解释

给定一个最多 5000 × 5000 5000\times 5000 5000×5000的地图,给出地图上一些目标点(这些点都有价值val),给你一个正方形去框选地图上的目标点,并问所能框选到的目标点之和的最大值是多少。


思路分析

s [ i ] [ j ] s[i][j] s[i][j]表示地图上从坐标 ( 1 , 1 ) (1,1) (1,1)到坐标 ( i , j ) (i,j) (i,j)的所有目标点的价值之和。

问题:如何求出一块特定的正方形内的所有目标点的价值之和呢?

在这里插入图片描述

例如上图,假设我们想要求出蓝色正方形内的所有目标点的价值之和,那么只需要用大正方形-两个红色的长方形+绿色正方形。R是要枚举的正方形的边长。

  • 大正方形: s [ i ] [ j ] s[i][j] s[i][j]

  • 上面的红色长方形: s [ i − R ] [ j ] s[i-R][j] s[iR][j]

  • 左边的红色长方形: s [ i , j − R ] s[i,j-R] s[i,jR]

  • 蓝色的小正方形: s [ i ] [ j ] − s [ i − R ] [ j ] − s [ i ] [ j − R ] + s [ i − R ] [ j − R ] s[i][j]-s[i-R][j]-s[i][j-R]+s[i-R][j-R] s[i][j]s[iR][j]s[i][jR]+s[iR][jR]


    细节

    问题1:半径R的范围?

    因为题目给定的地图最大是 5000 × 5000 5000\times 5000 5000×5000,所以R的最大范围应该也是5000.但是因为我们求前缀和数组时,R是从1到5001,即范围是5000.因此,如果我们输入的R是 ≥ 5001 \geq 5001 5001,那么就应该让 R = m i n ( R , 5001 ) R=min(R,5001) R=min(R,5001),因为如果R的范围超过了5000,那么这个炸弹的爆破范围一定是已经全部包括了 5000 × 5000 5000\times 5000 5000×5000的地图了。

    问题2:为什么是 s [ x ] [ y ] + = w s[x][y]+=w s[x][y]+=w?

    因为同一个坐标的的位置上,可能会有多个目标点,所以要对这个位置累加其上的所有目标点的价值。因此,为了防止同一个位置上有多个目标点,要写成 s [ x ] [ y ] + = w s[x][y]+=w s[x][y]+=w,而不能写成 s [ x ] [ y ] = w s[x][y]=w s[x][y]=w

    问题3:为什么是 s [ i ] [ j ] + = s [ i − 1 ] [ j ] + s [ i ] [ j − 1 ] − s [ i − 1 ] [ j − 1 ] s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1] s[i][j]+=s[i1][j]+s[i][j1]s[i1][j1]

    首先,在求矩阵的前缀和时,我们一般都是用两个二维数组, a [ i ] [ j ] a[i][j] a[i][j]表示某个数值, s [ i ] [ j ] s[i][j] s[i][j]表示以坐标 ( i , j ) (i,j) (i,j)为右下角结尾的子矩阵里面全部数值的总和。然后我们一般是写成 s [ i ] [ j ] = s [ i − 1 ] [ j ] + s [ i ] [ j − 1 ] − s [ i − 1 ] [ j − 1 ] + a [ i ] [ j ] s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j] s[i][j]=s[i1][j]+s[i][j1]s[i1][j1]+a[i][j]。但是因为这道题内存卡得死,不能开两个数组。因此,只能开一个前缀和数组 s [ i ] [ j ] s[i][j] s[i][j]。然后,写成 s [ i ] [ j ] + = s [ i − 1 ] [ j ] + s [ i ] [ j − 1 ] + s [ i − 1 ] [ j ] − s [ i − 1 ] [ j − 1 ] s[i][j]+=s[i-1][j]+s[i][j-1]+s[i-1][j]-s[i-1][j-1] s[i][j]+=s[i1][j]+s[i][j1]+s[i1][j]s[i1][j1]可以理解成 s [ i ] [ j ] = s [ i − 1 ] [ j ] + s [ i ] [ j − 1 ] − s [ i − 1 ] [ j − 1 ] + s [ i ] [ j ] s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+s[i][j] s[i][j]=s[i1][j]+s[i][j1]s[i1][j1]+s[i][j]。因为 s [ N ] [ N ] s[N][N] s[N][N]前缀和数组是全局变量,所以初始值为0,可以把等式右边的 s [ i ] [ j ] s[i][j] s[i][j]看做是 a [ i ] [ j ] a[i][j] a[i][j]

    其实,更合理的解释,就是同一个坐标的位置,可能会有多个目标点,所以求对这个位置求前缀和时,要累加其上的所有目标点的价值。

    问题4:如何理解 r e s = m a x ( r e s , s [ i ] [ j ] − s [ i − R ] [ j ] − s [ i ] [ j − R ] + s [ i − R ] [ j − R ] ) res=max(res,s[i][j]-s[i-R][j]-s[i][j-R]+s[i-R][j-R]) res=max(res,s[i][j]s[iR][j]s[i][jR]+s[iR][jR])

    因为我们是对R从小到大枚举到5001,对于枚举到的R,看看这个 R × R R\times R R×R的正方形内所有目标点的价值总和,因为要枚举很多R,所有会有很多正方形,然后对这些枚举到的正方形,求 m a x max max,即可得到某个确定的 R × R R\times R R×R的正方形内所有目标点的价值总和,那么此时就是最大值。


    代码

    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N=5010;
    int s[N][N];	//前缀和数组
    int main()
    {
        int n,R;	//输入n个目标和边长R
        scanf("%d%d",&n,&R);
        R=min(R,5001);	//对R取最小值
        //输入n个目标点的信息
        for(int i=0;i<n;i++)
        {
            int x,y,w;	//坐标(x,y)、价值
            scanf("%d%d%d",&x,&y,&w);
            x++,y++;	//因为前缀和一般从1开始取,而题目输入的x和y是从0开始。所以要+1,方便处理前缀和数组
            s[x][y]+=w;	//一个位置上可能有多个目标,所以对这个位置累加其价值
        }
        //预处理前缀和
        for(int i=1;i<=5001;i++)
        {
            for(int j=1;j<=5001;j++)
            {
                s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
            }
        }
        int res=0;	//代表一颗炸弹最多能炸掉地图上目标的总价值数目。
        //枚举边长R,确定选择哪个R*R的正方形,可以使得总价值最大
        for(int i=R;i<=5001;i++)
        {
            for(int j=R;j<=5001;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;
    }
    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卷心菜不卷Iris

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值