《算法竞赛进阶指南》 第一章 Acwing 99. 激光炸弹 二维前缀和

地址 https://www.acwing.com/problem/content/description/101/

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

注意:不同目标可能在同一位置。

现在有一种新型的激光炸弹,可以摧毁一个包含 R×R 个位置的正方形内的所有目标。

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

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

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

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

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

数据范围
0≤R≤109
0<N≤10000,
0≤Xi,Yi≤5000
0≤Wi≤1000
输入样例:
2 1
0 0 1
1 1 1
输出样例:
1

 

解法

 

计算每个边长为r的正方形能覆盖的价值

使用二维前缀和进行区间计算的加速  V代表单个矩形的面积  W[i][j]代表从0,0坐标开始到i,j坐标的多个矩形的面积和

W[i][j] = W[i-1][j]+W[i][j-1] - W[i-1][j-1] + V[i][j]

减去W[i-1][j-1] 是因为 W[i-1][j]+W[i][j-1]中将前者加了两次 所以要减少一次

当我们计算完所有W[i][j]  那么利用前缀和公式可以快速的获取任意 左上坐标为jk到右下坐标的矩形面积和

 需要注意的点

1 为了计算前缀和方便 整个地图 xy均加上了1   因为前缀和有类似 a[i] = a[i]+a[i-1]的操作,i等于0要处理边界。 二维前缀和也类似

2 矩形能覆盖的图形只包括举证的下边和右边 不包括上边和左边。我怀疑是题目为了吻合前缀和的解法,强行解释数据的问题。

一个炸弹轰炸面积是正方形且还要边平行于XY轴 左上点是归属于W[i][j]  右下角点是归属于W[i+1][j+1]

一个边长是两者之差的炸弹矩形面积是无法同时包括两点 这就很诡异了 除了用前缀和解释。

3 给出的炸弹覆盖矩形范围的边长 大于整个地图,注意处理

 

#include <iostream>
using namespace std;


const int N = 5010;
int mm[N][N];
int n, r, len;

void solve() {
    for (int i = 0; i < len; i++) {
        for (int j = 0; j < len; j++) {
            int sum = mm[i][j];
            if (i > 0) { sum += mm[i - 1][j]; }
            if (j > 0) { sum += mm[i][j - 1]; }
            if (i > 0 && j > 0) { sum -= mm[i - 1][j - 1]; }
            mm[i][j] = sum;
        }
    }

    int ans = 0;
    for (int i = r - 1; i < len; i++) {
        for (int j = r - 1; j < len; j++) {
            int sum = mm[i][j];
            if (i >= r) { sum -= mm[i - r][j]; }
            if (j >= r) { sum -= mm[i][j - r]; }
            if (i >= r && j >= r) { sum += mm[i - r][j - r]; }
            ans = max(ans, sum);
        }
    }
    cout << ans << endl;
    return;
}

int main()
{
    cin >> n >> r;   int maxx = 0; int maxy = 0;
    for (int i = 0; i < n; i++) {
        int x, y, w;
        cin >> x >> y >> w;  mm[x][y] += w;
        maxx = max(x, maxx); maxy = max(y, maxy);
    }
    len = max(maxx, maxy) + 1;
    //    cout << len << " "<<maxx<<" "<<maxy<<endl;  return 0;
    r = min(len, r);
    solve();

    return 0;
}

 

  

posted on 2021-03-29 13:56  itdef  阅读(113)  评论(0编辑  收藏  举报

导航