[蓝桥杯 2018 省 A] 三体攻击

该问题是一个编程竞赛中的题目,涉及三维空间中的战舰布局和立方体攻击策略。给定战舰的防御值和一系列攻击参数,任务是确定第一艘因伤害超过防御力而爆炸的战舰是在哪一轮攻击之后。解题方法包括使用差分数组来跟踪每艘战舰的累计伤害,并通过二分查找找到最早发生爆炸的轮次。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[蓝桥杯 2018 省 A] 三体攻击

题目描述

三体人将对地球发起攻击。为了抵御攻击,地球人派出了 A×B×CA\times B\times CA×B×C 艘战舰,在太空中排成一个 AAABBBCCC 列的立方体。其中,第 iii 层第 jjj 行第 kkk 列的战舰(记为战舰 (i, j, k)(i, j, k)(i,j,k))的生命值为 d(i, j, k)d(i, j, k)d(i,j,k)

三体人将会对地球发起 mmm 轮“立方体攻击”,每次攻击会对一个小立方体中的所有战舰都造成相同的伤害。具体地,第 ttt 轮攻击用 777 个参数 lat, rat, lbt, rbt, lct, rct, htla_t, ra_t, lb_t, rb_t, lc_t, rc_t, h_tlat,rat,lbt,rbt,lct,rct,ht 描述;

所有满足 i∈[lat, rat],j∈[lbt, rbt],k∈[lct, rct]i\in [la_t, ra_t],j\in [lb_t, rb_t],k\in [lc_t, rc_t]i[lat,rat],j[lbt,rbt],k[lct,rct] 的战舰 (i, j, k)(i, j, k)(i,j,k) 会受到 hth_tht 的伤害。如果一个战舰累计受到的总伤害超过其防御力,那么这个战舰会爆炸。

地球指挥官希望你能告诉他,第一艘爆炸的战舰是在哪一轮攻击后爆炸的。

输入格式

从标准输入读入数据。

第一行包括 444 个正整数 AAABBBCCCmmm

第二行包含 A×B×CA\times B\times CA×B×C 个整数,其中第 ((i − 1)×B+(j − 1))×C+(k − 1)+1((i − 1)\times B + (j − 1)) \times C + (k − 1)+1((i 1)×B+(j 1))×C+(k 1)+1 个数为 d(i, j, k)d(i, j, k)d(i,j,k)

333 到第 m + 2m + 2m+ 2 行中,第 (t + 2)(t + 2)(t+ 2) 行包含 777 个正整数 lat, rat, lbt, rbt, lct, rct, htla_t, ra_t, lb_t, rb_t, lc_t, rc_t, h_tlat,rat,lbt,rbt,lct,rct,ht

输出格式

输出到标准输出。

输出第一个爆炸的战舰是在哪一轮攻击后爆炸的。保证一定存在这样的战舰。

样例 #1

样例输入 #1

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

样例输出 #1

2

提示

【样例解释】

在第 222 轮攻击后,战舰 (1,1,1)(1,1,1)(1,1,1) 总共受到了 222 点伤害,超出其防御力导致爆炸。

【数据约定】

对于 10%10\%10% 的数据,B=C=1B = C = 1B=C=1

对于 20%20\%20% 的数据,C=1C = 1C=1

对于 40%40\%40% 的数据,A×B×C, m≤10000A\times B \times C, m\le10000A×B×C,m10000

对于 70%70\%70% 的数据,A, B, C ≤ 200A, B, C \le 200A,B,C 200

对于所有数据,1≤A×B×C≤ 1061\le A\times B\times C \le 10^61A×B×C 1061≤m≤ 1061\le m \le 10^61m 1060≤ (i, j, k)0 \le  (i, j, k)0(i,j,k), ht≤ 109h_t\le 10^9ht 109

思路

三维差分
在这里插入图片描述
【差分数组求法】

// 在考虑差分数组的时候考虑规律更容易理解一点
// (x1, y1, z1)和(x2, y2, z2)之间的原序列都加上c,对数组b的影响:
// 偶数个1是加的话那么奇数个1就减 下方代码中的add和sub函数就是如此
b[x1    ][y1    ][z1    ]   += c;  // 000
b[x1    ][y1    ][z2 + 1]   -= c;  // 001
b[x1    ][y2 + 1][z1    ]   -= c;  // 010
b[x1    ][y2 + 1][z2 + 1]   += c;  // 011
b[x2 + 1][y1    ][z1    ]   -= c;  // 100
b[x2 + 1][y1    ][z2 + 1]   += c;  // 101
b[x2 + 1][y2 + 1][z1    ]   += c;  // 110
b[x2 + 1][y2 + 1][z2 + 1]   -= c;  // 111

代码

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 2e6 + 10;

int A, B, C, m; //层,行,列
int s[N], b[N], op[N / 2][7], tmp[N]; //前缀和,差分数组,操作数,

int get(int i, int j, int k) {
	return (i * B + j) * C + k;
}

//求解差分数组函数
void add(int x1, int x2, int y1, int y2, int z1, int z2, int c) {
	b[get(x1, y1, z1)] += c;
	b[get(x1, y1, z2 + 1)] -= c;
	b[get(x1, y2 + 1, z1)] -= c;
	b[get(x1, y2 + 1, z2 + 1)] += c;
	b[get(x2 + 1, y1, z1)] -= c;
	b[get(x2 + 1, y1, z2 + 1)] += c;
	b[get(x2 + 1, y2 + 1, z1)] += c;
	b[get(x2 + 1, y2 + 1, z2 + 1)] -= c;
}

//进行攻击函数
void sub(int x1, int x2, int y1, int y2, int z1, int z2, int c) {
	tmp[get(x1, y1, z1)] -= c;
	tmp[get(x1, y1, z2 + 1)] += c;
	tmp[get(x1, y2 + 1, z1)] += c;
	tmp[get(x1, y2 + 1, z2 + 1)] -= c;
	tmp[get(x2 + 1, y1, z1)] += c;
	tmp[get(x2 + 1, y1, z2 + 1)] -= c;
	tmp[get(x2 + 1, y2 + 1, z1)] -= c;
	tmp[get(x2 + 1, y2 + 1, z2 + 1)] += c;
}

bool check(int mid) {
	//将tmp数组初始化为b数组
	memcpy(tmp, b, sizeof b);
	//进行攻击
	for (int i = 0; i < mid; i++) {
		int x1 = op[i][0], x2 = op[i][1], y1 = op[i][2], y2 = op[i][3],
		    z1 = op[i][4], z2 = op[i][5], c = op[i][6];
		sub(x1, x2, y1, y2, z1, z2, c);
	}
	memset(s, 0, sizeof s);
	for (int i = 1; i <= A; i++)
		for (int j = 1; j <= B; j++)
			for (int k = 1; k <= C; k++) {
				s[get(i, j, k)] = tmp[get(i, j, k)] +
				                  s[get(i - 1, j, k)] + s[get(i, j - 1, k)] - s[get(i - 1, j - 1, k)]
				                  + s[get(i, j, k - 1)] - s[get(i - 1, j, k - 1)] - s[get(i, j - 1, k - 1)]
				                  + s[get(i - 1, j - 1, k - 1)];
				if (s[get(i, j, k)] < 0)
					return true;
			}
	return false;
}

int main() {
	cin >> A >> B >> C >> m;
	for (int i = 1; i <= A; i++)
		for (int j = 1; j <= B; j++)
			for (int k = 1; k <= C; k++) {
				cin >> s[get(i, j, k)];
				//创建差分数组
				add(i, i, j, j, k, k, s[get(i, j, k)]);
			}
	//读入操作数组
	for (int i = 0; i < m; i++)
		for (int j = 0; j < 7; j++)
			cin >> op[i][j];
	//二分答案
	int l = 1, r = m;
	while (l < r) {
		int mid = l + r >> 1;
		if (check(mid))
			r = mid;
		else
			l = mid + 1;
	}
	cout << l << endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值