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]$。
容易得到:
同理,对于任意一个边长为 \(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) 收藏 举报
浙公网安备 33010602011771号