计蒜客 2020 蓝桥杯大学模拟赛(一) 被袭击的村庄

  •  1000ms
  •  262144K

邪恶势力要进攻 AA 村了!

AA 村是一个 n*mn∗m 的矩形,每个点上是道路、房屋、田地三者其一,耐久度分别是 a,b,ca,b,c。

邪恶势力要进行 qq 次攻击,每次攻击都是使用炮弹对村庄进行轰炸。

邪恶势力有两种炮弹,分别是普通炮弹(编号为 11 )和高级炮弹(编号为 00 )。两种炮弹的攻击范围都是 k\times kk×k 的方形,其中方形中心是炮弹落地点。炮弹对攻击范围内每个格子造成的损害不一定一样,用一个 k\times kk×k 的矩阵描述,每个数字表示对对应格子造成的伤害。高级炮弹和普通炮弹的伤害矩阵相同。

上述矩阵描述的是直接攻击的伤害。对于高级炮弹,它的攻击会造成溅射伤害:如果这个格子被直接攻击,那么周围八个格子都会受到溅射伤害,造成的伤害是 ww 。所以一个高级炮弹可能对同一个格子进行多次伤害。溅射伤害不会继续造成溅射伤害。普通炮弹不造成溅射伤害。

不论是直接攻击的伤害还是溅射造成的伤害,都会使耐久度下降,下降量等于伤害的大小。耐久度最多降为 00,一个建筑单位受到的伤害定义为耐久度的减少量

如果攻击范围涉及到地图边界外,那么不予计算(溅射伤害也不会计算)。

现在,给定上述的所有信息,我们想知道 AA 村被袭击之后的道路、房屋、田地的总伤害,以及全村的总伤害。

输入格式

第一行两个整数 n,mn,m,表示 A 村大小。

接下来一行三个整数 a,b,ca,b,c。

接下来一行两个整数 k,wk,w。

接下来 kk 行,每行 kk 个数,描述高级炮弹和普通炮弹对相对位置所造成的伤害。

接下来一个 n\times mn×m 的矩阵,表示 AA 村的布局。 11 表示道路, 22 表示房屋, 33 表示田地。

接下来一个数 qq,表示邪恶势力要进行 qq 轮攻击。

接下来 qq 行,每行三个数 id,x,yid,x,y,分别是炮弹的编号以及他所攻击的矩阵的中心位置的 xx 坐标、 yy 坐标,即第 xx 行 yy 列。

输出格式

第一行三个整数,分别是对道路、房屋、田地造成的总伤害

第二行一个整数,表示对全村造成的伤害。

数据范围

kk 一定是奇数。

对于 30\%30% 的数据:1 \leq n,m,k,q \leq 501≤n,m,k,q≤50

对于 100\%100% 的数据:1 \leq n,m,k,q \leq 300, 1 \leq a,b,c,w \leq 10000000001≤n,m,k,q≤300,1≤a,b,c,w≤1000000000

样例输入复制

3 3
1 1 1
3 1
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
1
1 2 2

样例输出复制

9 0 0

思路:模拟,有几个坑点要注意。

坑点一:“第一行三个整数,分别是对道路、房屋、田地造成的总伤害”  这个总伤害指的居然是被完全破坏的道路、房屋、田地的个数?

“第二行一个整数,表示对全村造成的伤害。”这个总伤害才是炮弹造成的伤害总数。

坑点二:注意范围,要用long long 运算,并且不能让hp < 0 的地方一直减,因为重复溅射部分地点hp会小于long long 最小值,变成正数。

#include <bits/stdc++.h>

using namespace std;

const int N = 310;

int n,m,a,b,c,k,w;

int g[N][N];

int gg[N][N];

int hurt[N][N];

int ans[4];

bool inmap(int x, int y)
{
	if(x >= 1 && x <= n && y >= 1 && y <= m) return 1;
	return  0;
}

void js(int x, int y)
{
	for(int i=-1; i<=1; i++)
		for(int j=-1; j<=1; j++)
		{
			if(i == 0 && j == 0) continue;
			if(inmap(x+i, y+j))
			{    
				if(gg[x+i][y+j] > 0) 
					gg[x+i][y+j] -= w;
			}
		}
}

void attack(int id, int x, int y)
{
	for(int i=-k/2; i<=k/2; i++)
		for(int j=-k/2; j<=k/2; j++)
		{
			if(inmap(x+i, y+j))
			{
				if(gg[x+i][y+j] > 0) gg[x+i][y+j] -= hurt[i+k/2+1][j+k/2+1];
				if(!id) js(x+i,y+j);
			}			
		}
}

int main()
{
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	
	cin>>n>>m>>a>>b>>c>>k>>w;
	
	for(int i=1; i<=k; i++)
		for(int j=1; j<=k; j++)
			cin>>hurt[i][j];
	
	for(int i=1; i<=n; i++)
		for(int j=1; j<=m; j++)
		{
			cin>>g[i][j];
			if(g[i][j] == 1) gg[i][j] = a;
			else if(g[i][j] == 2) gg[i][j] = b;
			else gg[i][j] = c;
		}
	
	int q;
	cin>>q;
	
	while(q--)
	{
		int id,x,y;
		cin>>id>>x>>y;		
		attack(id, x, y);
	}
	
	long long sum = 0;
	
	for(int i=1; i<=n; i++)
	{
		for(int j=1; j<=m; j++)
		{
            ans[g[i][j]] += gg[i][j] <= 0 ? 1 : 0;   
			if(g[i][j] == 1)
			{
				sum += a - max(0, gg[i][j]);
			}
			else if(g[i][j] == 2)
			{
				sum += b - max(0, gg[i][j]);
			}
			else
			{
				sum += c - max(0, gg[i][j]);
			}
		}
	}
	
	cout<<ans[1]<<' '<<ans[2]<<' '<<ans[3]<<endl<<sum;
		
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值