首页 > 其他分享 >炸弹 (boom.c)(100分双端递推+分割线优化)

炸弹 (boom.c)(100分双端递推+分割线优化)

时间:2025-01-10 18:28:47浏览次数:3  
标签:int 双端 炸弹 坐标 魔物 left 分割线 boom

炸弹 (boom.c)

时间限制: 800ms
内存限制: 256000KiB
进度: 57/12406 = 0.5%

题目描述

出题助教: Sakiyary
验题助教: Corax、XiEn、ErinwithBMQ、runz、MacGuffin、Bob

维多利亚的腐烂荒野上出现了 N 个魔物,你和小维需要抓紧时间调配炸弹对付它们。

荒野可以视为一张方格图,(x_i, y_i, h_p_i) 表示魔物 i 出现在方格 (xi​,yi​) 上,其生命值为整数 h_p_i。每个方格最多出现一个魔物。

你们可以调配炸弹的 爆炸范围 与 爆炸伤害 两个参数:

  • 爆炸范围 是一个任意位置、由方格作为单元组成的、任意大小的矩形,最小为 1×1 的方格;
  • 爆炸伤害 是一个整数值。

为了消灭爆炸范围内的所有魔物,爆炸伤害至少要等于该爆炸范围内魔物生命值的最大值。

假设炸弹 爆炸范围 的面积为 S,爆炸伤害为 D,则调配该炸弹所需要的材料量为 S×D。

为了抓紧时间并减少炸弹的总材料消耗,你们决定调配两个炸弹,将魔物划分为左右两批,两人各用一个炸弹对付其中一批,即两个炸弹的爆炸范围在 x 轴上的投影不重叠。

输入格式

输入共 N+1 行:

  • 第一行包含一个正整数,表示魔物的数量 N;
  • 接下来有 N 行,每行包含三个非负整数,以空格隔开,分别表示当前魔物 i 所处方格的 xi​ 坐标、yi​ 坐标以及魔物的生命值 hpi​。

输出格式

输出共一行,包含一个整数,为调配两个炸弹时所需的最小总材料量。

测试样例

InputOutput
5 
0 3 1 
0 1 2 
5 1 3 
1 2 4 
4 3 554
5 
0 2 9 
4 1 1 
2 3 1 
2 0 1 
2 1 10121

思路:

1.暴力会超时,所以我们需要优化寻找最大hp,最高,最低。我们可以采用递推的方法,以左半部分举例子,储存好前一步的hp,高,低,对于向右移动的x坐标划分线,我们只要比较新的x轴坐标划分线的hp,高,低。与原先比较即可。

2.由于暴力分的数组,会存在连续相等的x坐标,对于递推是很不方便的。所以我换了一种去重储存怪物坐标的点。用一个结构体类型的数组,储存每一个x坐标分割线上的最高值,最低值还有最大的HP值。这样就可以进行递推了。

3.但是很快,我们就会发现,只能对左半部分的进行递推,右半部分却只能遍历寻找上部分,下部分,最大HP。由于分割线是两个部分一起的,左半部分右边界是闭,右半部分左边界是开,所以我们可以从右往左递推,以及之前的从左往右递推。记录每一个x作为分割线上,左(右)部分需要的材料。这样就需要两个数组来储存。最后遍历存在的最左边界x到最右边界x,依次相加两个部分的材料,通过比较求出最小材料。

4.有人可能会问?好像只用到了排序的最左边界和最右边界啊?那是不是只要找到最左边界x最右边界x就行了,不需要特地排序,我的理解是,有些x分割线上是没有怪兽的,以存在怪兽的分割线更快找到最小材料。所以只要在有怪物的x分割线上做文章就好了。

代码如下:

#include<iostream>
#include<vector> 
#include<algorithm>
using namespace std;
struct node{
	int yhigh =-1e9 ;
	int ylow = 1e9;
	int HP;
};
int ans = 1e9;
int n;
const int L = 1e6;
int monster[L];
bool mem[L];//去重x坐标数组 
int left_half[L];//记录每一个x分割线的左半部分数组 
int right_half[L]; //记录每一个x分割线的右半部分数组 
node list[L]; 
int num = 0;//计数存在的x数量 

int Dl;//左半部分最大生命值 
int high_left = -1;
int low_left = 1e9;
int cntl(int x)///左半部分 
{
	int S; 
	int left = monster[1];
	int right = x;
	high_left = max(high_left,list[x].yhigh);
	low_left = min(low_left,list[x].ylow);
	S = (right - left +1) * (high_left - low_left + 1);
	Dl = max(Dl,list[x].HP);
	
/*	cout << "左半部分左边界:" << left << endl;
	cout << "左半部分右边界:" << right << endl;
	cout << "左半部分上边界:" << high_left << endl;
	cout << "左半部分下边界:" << low_left << endl;
	cout << "左半部分高度差:" << high_left - low_left + 1 << endl;
	cout << "左半部分长度差:" << right - left + 1 << endl;
	cout << "左半部分最大生命值:" << Dl << endl;*/
	return S*Dl;
}

int Dr;//右半部分最大生命值
int high_right = -1;
int low_right = 1e9;
int cntr(int x)//右半部分 
{
	int S;
	int left = x;
	int right = monster[num];
	high_right = max(high_right,list[x].yhigh);
	low_right = min(low_right,list[x].ylow);
	S = (right - left + 1) * (high_right - low_right + 1);
	Dr = max(Dr,list[x].HP);
	return S*Dr;
 } 
int main(void)
{
	cin >> n;
	for(int i = 1 ; i <= n ; i++)
	{
		int x,y,hp;
		cin >> x >> y >> hp;
		if(!mem[x])
		{
			mem[x] = true;
			monster[++num] = x;//储存存在的x坐标 	
//			cout << "存入" << x << "在" << num <<endl;
		}
		if(list[x].yhigh < y)//储存x坐标上的最高点 
		list[x].yhigh = y;

		if(list[x].ylow > y)//储存x坐标上的最低点 
		list[x].ylow = y;

		if(list[x].HP < hp)//储存x坐标上最大的生命值 
		list[x].HP = hp; 
	}
	
	sort(monster+1,monster+1+num); //升序排序出现的坐标x分割线
	
/*	for(int i = 0 ; i <= monster[num] ;i++)
	{
	cout << "第" << i << "为分界线的最高" << list[i].yhigh << " " << endl;//正确  
	cout << "第" << i << "为分界线的最低" << list[i].ylow << " " << endl;  //正确 
	}*/

//	cout << monster[i] << " " << endl; 排序正确 

	for(int i = 1 ; i <= num - 1 ; i++)//左半部分右边界是闭 
	{
		left_half[monster[i]] = cntl(monster[i]);
	} 
	for(int i = num - 1 ; i >= 1 ; i--)//右半部分左边界是开 
	{
		right_half[monster[i]] = cntr(monster[i+1]);
	}
	
	for(int i = 1 ; i <= num - 1 ; i++)
	{
		ans = min(ans,left_half[monster[i]] + right_half[monster[i]]);//比较每一个x分割线的左半部分和右半部分的和,找出最小。 
	}
	cout << ans;
	return 0;
 }

因为只测试过样例,有错误请指出!

 

 

标签:int,双端,炸弹,坐标,魔物,left,分割线,boom
From: https://blog.csdn.net/zqystca/article/details/145043347

相关文章

  • 炸弹 (boom.c)
    炸弹(boom.c)时间限制:800ms内存限制:256000KiB进度:57/12406=0.5%题目描述出题助教:Sakiyary验题助教:Corax、XiEn、ErinwithBMQ、runz、MacGuffin、Bob维多利亚的腐烂荒野上出现了 N 个魔物,你和小维需要抓紧时间调配炸弹对付它们。荒野可以视为一张方格图,(......
  • 【华为OD-E卷-最小调整顺序次数、特异性双端队列 100分(python、java、c++、js、c)】
    【华为OD-E卷-最小调整顺序次数、特异性双端队列100分(python、java、c++、js、c)】题目有一个特异性的双端队列,该队列可以从头部或尾部添加数据,但是只能从头部移出数据。小A依次执行2n个指令往队列中添加数据和移出数据。其中n个指令是添加数据(可能从头部添加、也可能从......
  • 8 位 RISC 模型机 状态机控制 ALU双端口
    8位RISC模型机状态机控制双端口项目地址:8位RISC模型机状态机控制双端口从8位寄存器(D触发器)开始DDD:8位输入......
  • 双端之Nginx+Php结合PostgreSQL搭建Wordpress
    第一台虚拟机:安装Nginx更新系统包列表:sudoaptupdate安装Nginx及php扩展:sudoaptinstallnginxphp-fpmphp-pgsqlphp-mysqli-y启动Nginx服务:sudosystemctlstartnginx检查Nginx是否正常运行:xdg-openhttp://localhost注意:终端命令打开网址打......
  • (免费源码)spring boot 双端融合的教学过程管理系统小程序66431 计算机毕业设计必看必学
     springboot双端融合的教学过程管理系统小程序摘 要随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,双端融合的教学过程管理系统小程序被用户普遍使用,为方便用户能够可以......
  • 24年最新版云开发壁纸小程序源码/新版大气UI微信QQ双端壁纸小程序源码
    内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍本壁纸表情包头像小程序采用(dcloud云开发)所以无需服务器与域名支持微信QQ双端小程序也就是说可以打包成微信小程序也可以打包成QQ小程序相当于一码二用,非常划算无需授权,......
  • LZC3106A国产高性能、高精度谐振模式双端控制器,专用LLC半桥谐振电路的控制应用
    综合描述LZC3106是一款高性能、高精度谐振模式双端控制器,专用于LLC半桥谐振电路的控制应用。它提供50%的互补占空比:高压侧开关和低压侧开关在完全相同的时间内以180°反相方式导通/关断。控制器通过调节系统工作频率来实现对输出电压的调制和稳定.LZC3106......
  • 算法练习题09:滑动窗口最大值(队列、双端队列)
    classSolution{publicint[]maxSlidingWindow(int[]nums,intk){if(nums==null||nums.length==0){returnnewint[0];}intn=nums.length;int[]result=newint[n-k+1];Deque<Integer&......
  • huawei0821笔试第二题笔记:双端队列deque
    intsolve(deque<int>machines,constvector<int>&tasks){for(inttask:tasks){intcnt=0;//首件不匹配while(cnt<machines.size()&&task!=machines.front()){machines.push_back(machines.......
  • 数据结构(C)---双端队列(Deque)
    在使用本博客提供的学习笔记及相关内容时,请注意以下免责声明:信息准确性:本博客的内容是基于作者的个人理解和经验,尽力确保信息的准确性和时效性,但不保证所有信息都完全正确或最新。非专业建议:博客中的内容仅供参考,不能替代专业人士的意见和建议。在做出任何重要决定之前,请咨询相......