DestinHistoire

 

BZOJ-1218 激光炸弹(二维前缀和)

题目描述

  一种新型的激光炸弹,可以摧毁一个边长为 \(R\) 的正方形内的所有的目标。现在地图上有 \(n(n\leq 10^4)\) 个目标,用整数 \(X_i,Y_i\)(其值在 \([0,5000]\))表示目标在地图上的位置,每个目标都有一个价值。激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆破范围,即那个边长为 \(R\) 的正方形的边必须和 \(x,y\) 轴平行。若目标位于爆破正方形的边上,该目标将不会被摧毁。求一棵炸弹最多能炸掉地图上总价值为多少的目标。

分析

  用 \(A[i][j]\) 表示位置 \((i,j)\) 上所有目标价值之和,即 \(A[X_i][Y_i]+=W_i\)。

  求 \(A\) 的二维前缀和 $ S[i][j]=\displaystyle\sum_{x=1}{i}\sum_{y=1}A[x][y]$。

  容易得到:

\[S[i][j]=S[i-1][j]+S[i][j-1]-S[i-1][j-1]+A[i][j] \]

  同理,对于任意一个边长为 \(R\) 的正方形,有:

\[\sum_{x=i-R+1}^{i}\sum_{y=j-R+1}^{j}A[x][y]=S[i][j]-S[i-R][j]-S[i][j-R]+S[i-R][j-R] \]

  \(O(n^2)\) 枚举边长为 \(R\) 的正方形的右下角坐标 \((i,j)\),\(O(1)\) 计算正方形内价值之和。

  由于求前缀和时把 \((X_i,Y_i)\) 当成了一个格子,但 \((X_i,Y_i)\) 实际上是一个点,而且边上的目标不会被炸毁,所以统计 $(X_i,Y_i) $ 上的价值和的时候需要令 \(A[X_i+1][Y_i+1]+=W_i\)。

代码

#include<bits/stdc++.h>
using namespace std;
int S[5010][5010];
int main()
{
    int n,R;
    cin>>n>>R;
    for(int i=1;i<=n;i++)
    {
        int X,Y,W;
        scanf("%d %d %d",&X,&Y,&W);
        S[X+1][Y+1]+=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]+S[i][j];
    int ans=-1;
    for(int i=R;i<=5001;i++)
        for(int j=R;j<=5001;j++)
            ans=max(ans,S[i][j]-S[i-R][j]-S[i][j-R]+S[i-R][j-R]);
    cout<<ans<<endl;
    return 0;
}

posted on 2020-11-16 22:25  DestinHistoire  阅读(128)  评论(0)    收藏  举报

导航