【AcWing 99】激光炸弹——二维前缀和

时间:2019-08-06
本文章向大家介绍【AcWing 99】激光炸弹——二维前缀和,主要包括【AcWing 99】激光炸弹——二维前缀和使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

(题面来自AcWing)

一种新型的激光炸弹,可以摧毁一个边长为 R 的正方形内的所有的目标。

现在地图上有 N 个目标,用整数Xi,Yi表示目标在地图上的位置,每个目标都有一个价值Wi

激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆炸范围,即那个边长为 R的正方形的边必须和xy轴平行。

若目标位于爆破正方形的边上,该目标不会被摧毁。

求一颗炸弹最多能炸掉地图上总价值为多少的目标。

输入格式

第一行输入正整数 N 和 R ,分别代表地图上的目标数目和正方形的边长,数据用空格隔开。

接下来N行,每行输入一组数据,每组数据包括三个整数Xi,Yi,Wi,分别代表目标的x坐标,y坐标和价值,数据用空格隔开。

输出格式

输出一个正整数,代表一颗炸弹最多能炸掉地图上目标的总价值数目。

数据范围

0<N10000,
0Xi,Yi5000

   

  二维前缀和之后暴力枚举每个方形即可。两个坑点:

  1、首先要记录xi、yi的最大值n、m,将n和m作为地图右下端点的边界来枚举。由于边长没有给出范围,r有可能会大于整个地图的尺寸,因此n和m的初值要设为r。

  2、原本的地图是在格点上放置炸弹的,并且边界不能纳入爆炸范围,不好处理。我们考虑换个角度考虑问题,对地图进行转化:固定格点上的目标,把整个“棋盘”看作向右下方移动了(0.5, 0.5)个单位。这样的话,每个目标都处于移动后棋盘格子的中心,每次只要枚举一个边长为r-1的方形内的和就可以把原本方形可以炸到的目标纳入计算中。这个操作并不好想像,建议自己模拟一下来验证。

代码:

  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <cctype>  
  4. #define rep(i, a, b) for(int i = a; i <= b; ++i)  
  5. #define per(i, b, a) for(int i = b; i >= a; --i)  
  6. #define maxn 5010  
  7. using namespace std;  
  8. int s[maxn][maxn], n, r;  
  9. int main() {  
  10.     cin >> n >> r;  
  11.     int N = r, M = r, u, v, w;  
  12.     rep(i, 1, n) {  
  13.         cin >> u >> v >> w;  
  14.         ++u, ++v;  
  15.         s[u][v] += w;  
  16.         N = max(N, u), M = max(M, v);  
  17.     }  
  18.     rep(i, 1, N)  
  19.         rep(j, 1, M)  
  20.             s[i][j] += s[i-1][j] + s[i][j-1] - s[i-1][j-1];  
  21.     int ans = 0;  
  22.     rep(i, r, N)  
  23.         rep(j, r, M)   
  24.             ans = max(ans, s[i][j] - s[i-r][j] - s[i][j-r] + s[i-r][j-r]);  
  25.     cout << ans;  
  26.     return 0;  
  27. }  

原文地址:https://www.cnblogs.com/TY02/p/11307584.html