激光炸弹

*一种新型的激光炸弹,可以摧毁一个边长为 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;
}

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