(枚举)(模拟)(二位前缀和)99. 激光炸弹

简介: (枚举)(模拟)(二位前缀和)99. 激光炸弹

题目链接

99. 激光炸弹 - AcWing题库

一些话

切入点

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

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

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

1. 求一个矩阵内值的总和,符合二维前缀和的前提条件


2.求符合条件情况的最值,符合枚举的特征


3.写法复杂,条件多,符合模拟的特征


数据范围


0≤R≤1e9

0<N≤10000

0≤Xi,Yi≤5000

0≤Wi≤1000


1. xi,yi<5e3,可能用到双循环枚举


二维数组


流程

1.模拟题,列出伪代码

1.1读题得条件

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

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

不能直接用cin读值,要先用一个变量储存后再加入这个坐标对应的二维数组里


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


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


可以枚举一个坐标然后直接运算表示矩阵


1.2伪代码:枚举部分

1.2.1确定要枚举什么,如何缩小范围


1.题目要求一个与xy轴平行的矩阵值的总和最值,所以要枚举这个矩阵,矩阵边长是确定的,可以通过枚举一个顶点来表示整个矩阵,用二维前缀和求矩阵总和,只要枚举左上角的顶点然后通过坐标运算就可以表示出右下角的顶点


2.枚举边界超过最大的x,y,r时没有意义,所以只要取x,r,y,r的最大值即可


3.r的范围到1e9,但是x,y最大只有5e3,超过5e3的部分可以直接舍弃,r取5e3+1和r的最小值即可,在确认n,m前进行


1.2.3数据读入部分

题目x,y从0开始,因为要用前缀和,前缀和里有减1的操作,所以读入的坐标要先++才能用

w储存读入的值,然后加入到二维数组

1.2.2前缀和部分

双循环预处理前缀和数组,然后用枚举的坐标查询前缀和,与maxn比较

2.核验数据范围,

1.5e3可以开一个二维数组,

2.答案最多是n*w = 1e7,不用开long long

套路

1.相距为r的坐标的运算

相距为r的两个点a(x1,y1),b(x2,y2)

x2 = x1 + r - 1;

y2 = x2 + r - 1;

2.二维前缀和

//预处理
for(int i = 1;i <= n;i++){
    for(int j = 1;j <= n;j++){
        s[i][j] += s[i-1][j] + s[i][j-1] - s[i-1][j-1];
    }
}
// 查询左上角坐标(x1,y1),右上角坐标(x2,y2)
int res;
res = s[x1][y1] - s[x1-1][y2] - s[x2][y1-1] + s[x1-1][y1-1];

ac代码

// 12:31 - 12 : 41
// 21:39 ~21:42
// 14:45~15:03
// 不能用cin读值,要加等于,x,y+r太大时变小,找最大x,y,r来确定边界
// 枚举左上角得右下角,输出前缀和
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
const  int N = 5e3 + 10;
int n,m,r;
int s[N][N];//5e3+10级别的二维数组开不了longlong,只能开一个数组
int maxn = -0x3f3f3f3f;
int main(){
    int t;
    cin >> t >> r;
    r = min(5001,r);//双循环的最大值,因为要枚举坐标,所以边界不能太大
    n = m = r;
    while(t--){
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);
        x++,y++;
        s[x][y] += w;
        n = max(x,n);
        m = max(y,m);
    }
    for(int i = 1;i <= n;i++){
        for(int j = 1;j <= m;j++){
            s[i][j] += s[i][j-1] + s[i-1][j] - s[i-1][j-1];
        }
    }
    for(int i = 1;i + r - 1 <= n;i++){
        for(int j = 1;j + r - 1<= m;j++){
            maxn = max(maxn,s[i+r-1][j+r-1] - s[i+r-1][j-1] - s[i-1][j+r-1] + s[i-1][j-1]);
        }
    }
    cout << maxn << endl;
    return 0;
}
目录
相关文章
|
6月前
|
存储 C语言
牛客网刷题总结(1.有序序列判断,2.获得月份天数,3.矩阵相等判定,4.矩阵转换,5.井字棋判断输赢,6.递归进行进制转化)
牛客网刷题总结(1.有序序列判断,2.获得月份天数,3.矩阵相等判定,4.矩阵转换,5.井字棋判断输赢,6.递归进行进制转化)
75 0
|
算法 机器人 C语言
【二分查找】分巧克力、机器人跳跃、数的范围
开始准备蓝桥杯啦!这是计划的一部分,每天都会更新一个专题的内容,内容参考自acwing蓝桥杯辅导课,有兴趣的uu们也可以自行观看
108 0
|
定位技术
【CCCC】L3-007 天梯地图 (30分),两次Dijkstra+路径打印(数据点2,4错因),90行最短题解
【CCCC】L3-007 天梯地图 (30分),两次Dijkstra+路径打印(数据点2,4错因),90行最短题解
177 0
|
5月前
|
C++
【洛谷 P2241】统计方形(数据加强版)题解(循环枚举)
该题目是1997年普及组的一道编程题,要求计算$n\times m$棋盘中的正方形和长方形数量(不计正方形)。输入包含两正整数$n,m\leq 5000$。输出为一行,两个正整数分别表示正方形和长方形数量。示例输入`2 3`,输出`8 10`。解题思路是将矩形数拆分为正方形数和长方形数,然后通过双重循环计算。AC代码使用C++编写,通过累加方法得出结果。
51 0
|
5月前
|
存储 索引
每日刷题——相遇、宝石(模拟+数学)、相助(模拟+数组)、相依(dp的优化)
每日刷题——相遇、宝石(模拟+数学)、相助(模拟+数组)、相依(dp的优化)
38 1
|
6月前
|
算法 测试技术 C#
【二进制求公约数】【数学】【数论】2543. 判断一个点是否可以到达
【二进制求公约数】【数学】【数论】2543. 判断一个点是否可以到达
|
6月前
|
人工智能 算法
前缀和算法题(区间次方和、小蓝平衡和、大石头的搬运工、最大数组和)
前缀和算法题(区间次方和、小蓝平衡和、大石头的搬运工、最大数组和)
|
C语言
【C语言刷题】喝汽水问题、上三角矩阵判定以及矩阵相等判定
【C语言刷题】喝汽水问题、上三角矩阵判定以及矩阵相等判定
79 0
【C语言刷题】喝汽水问题、上三角矩阵判定以及矩阵相等判定
|
人工智能 算法 测试技术
[蓝桥杯] 枚举、模拟和排列问题
[蓝桥杯] 枚举、模拟和排列问题
75 0
|
算法
【算法挨揍日记】day03——双指针算法_有效三角形的个数、和为s的两个数字
【算法挨揍日记】day03——双指针算法_有效三角形的个数、和为s的两个数字
52 0