激光炸弹

激光炸弹

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

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

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

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

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

输入格式

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

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

输出格式

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

数据范围
0<N≤10000,
0≤Xi,Yi≤5000

输入样例:
2 1
0 0 1
1 1 1

输出样例:
1*

时/空限制: 10s / 168MB

其实这是一道典型的二维前缀和的题目。

什么是前缀和呢?

我们先来看最简单的一维的前缀和,假设有一个数组:a[0]到a[n],用s[0]到s[n]表示a数组0到n的前缀和。

首先让s[0]=a[0],那么后面的前缀和s[i]就可以用s[i] = a[i] + s[i-1]来表示。

二维前缀和其实也差不多,假设有一个大小为 n*m 的矩阵,坐标为 i , j 的元素,前缀和s[ i ][ j ]就是点( i , j )与点

( 0 , 0 )形成的矩形内的所有元素之和。

重点:我们可以通过前缀和来求出任意一个小矩形的总元素之和。

有了这个知识自然这道题就迎刃而解。


#include<bits/stdc++.h>//万能头文件 
using namespace std;
int a[5001][5001],s[5001][5001];//a数组用来保存输入的数据,s数组用来求前缀和 
int main()
{
	int n,x,y,w,r,MAX=0,ans=0,k;//MAX用来求出需要求前缀和的边界值,避免循环多次超时 
	cin>>n>>r;
	for(int i=0;i<n;i++)
	{
		scanf("%d %d %d",&x,&y,&w);
		a[x][y]=w;
		if(x>MAX)
			MAX=x;
		if(y>MAX)
			MAX=y;
	}
	s[0][0]=a[0][0];
	for(int i=1;i<=MAX;i++)
	{
		s[0][i]=a[0][i]+s[0][i-1];
		s[i][0]=a[i][0]+s[i-1][0];
	}
	for(int i=1;i<=MAX;i++)
	{
		for(int j=1;j<MAX;j++)
		{
			s[i][j]=s[i-1][j]+s[i][j-1]+a[i][j]-s[i-1][j-1];//这里利用了动态规划的思想 
		}
	}
	for(int i=r-1;i<=MAX;i++)
	{
		for(int j=r-1;j<=MAX;j++)
		{
			if(i==r-1&&j==r-1)//用if else防止越界 
				k=s[i][j];
			else if(i+1-r<=0)
				k=s[i][j]-s[i][j-r];
			else if(j+1-r<=0)
				k=s[i][j]-s[i-r][j];
			else
				k=s[i][j]-s[i-r][j]-s[i][j-r]+s[i-r][j-r];
			if(k>ans)
				ans=k;
		}
	}
	printf("%d\n",ans);
	return 0;
}

有了这个代码所有样例基本都过了,但是并不能AC。。。。。。。。。。。。。。

提交时会发现提升你内存超限制了。。。。。。很坑

仔细想一下就会发现其实s数组是多余的,a数组用来求s数组的数据求过的数据就不需要了。

于是就有了下面这个代码

#include<bits/stdc++.h>
using namespace std;
int a[5001][5001];
int main()
{
	int n,x,y,w,r,MAX=0,ans=0,k;
	cin>>n>>r;
	for(int i=0;i<n;i++)
	{
		scanf("%d %d %d",&x,&y,&w);
		a[x][y]=w;
		if(x>MAX)
			MAX=x;
		if(y>MAX)
			MAX=y;
	}
	for(int i=1;i<=MAX;i++)
	{
		a[0][i]=a[0][i]+a[0][i-1];
		a[i][0]=a[i][0]+a[i-1][0];
	}
	for(int i=1;i<=MAX;i++)
	{
		for(int j=1;j<MAX;j++)
		{
			a[i][j]=a[i-1][j]+a[i][j-1]+a[i][j]-a[i-1][j-1];
		}
	}
	for(int i=r-1;i<=MAX;i++)
	{
		for(int j=r-1;j<=MAX;j++)
		{
			if(i==r-1&&j==r-1)
				k=a[i][j];
			else if(i+1-r<=0)
				k=a[i][j]-a[i][j-r];
			else if(j+1-r<=0)
				k=a[i][j]-a[i-r][j];
			else
				k=a[i][j]-a[i-r][j]-a[i][j-r]+a[i-r][j-r];
			if(k>ans)
				ans=k;
		}
	}
	printf("%d\n",ans);
	return 0;
}

其实这个代码还可以更加精简,这里我认为没有必要了(其实是懒),有需要的可以自行修改。

全部评论

相关推荐

勇敢的联想人前程似锦:如果我是你,身体素质好我会去参军,然后走士兵计划考研211只需要200多分。
点赞 评论 收藏
分享
牛客868257804号:九个中铁八个中建
点赞 评论 收藏
分享
秋招进行到现在终于能写总结了。完全没想到战线会拉这么长,过程会如此狼狈,不过更应该怪自己太菜了。好在所有的运气都用在了最后,也是有个去处。背景:双2本硕科班,无竞赛,本科一段研究所实习,硕士一段大厂暑期实习但无转正。技术栈是C++&nbsp;&amp;&nbsp;Golang,实习是客户端音视频(而且是鸿蒙端开发),简历两个C++项目一个Golang项目。主要投递岗位:后端,cpp软开,游戏服务端,测开,以及一些不拘泥于Java的岗位。从8月起总共投递123家公司,笔试数不清了,约面大约30家。offer/oc/意向:友塔游戏(第一个offer,面试体验很好,就是给钱好少南瑞继保(计算机科班点击就送(限男生),不...
乡土丁真真:佬很厉害,羡慕~虽然我还没有到校招的时候,也想讲一下自己的看法:我觉得不是CPP的问题,佬的背书双2,技术栈加了GO,有两段实习。投了123,面了30.拿到11个offer。这个数据已经很耀眼了。这不也是CPP带来的吗?当然也不止是CPP。至少来说在这个方向努力过的也会有好的结果和选择。同等学历和项目选java就会有更好的吗?我个人持疑问态度。当然CPP在方向选择上确实让人头大,但是我觉得能上岸,至于最后做什么方向,在我看来并不重要。至于CPP特殊,有岗位方向的随机性,java不是不挑方向,只是没得选而已。也希望自己以后校招的时候能offer满满
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务