[蓝桥杯 2018 省 A] 三体攻击
题目描述
三体人将对地球发起攻击。为了抵御攻击,地球人派出了 A×B×CA\times B\times CA×B×C 艘战舰,在太空中排成一个 AAA 层 BBB 行 CCC 列的立方体。其中,第 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 个正整数 AAA,BBB,CCC,mmm;
第二行包含 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, m≤10000;
对于 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^61≤A×B×C≤ 106,1≤m≤ 1061\le m \le 10^61≤m≤ 106,0≤ (i, j, k)0 \le (i, j, k)0≤ (i, j, k), ht≤ 109h_t\le 10^9ht≤ 109。
三维差分+压维+二分
#include <stdio.h>
using namespace std;
int A, B, C, n, m;
const int N = 1e6 + 5;
int s[N]; // 舰队生命值
int D[N]; // 三维差分数组(压维后),同时用来计算每个点收到的攻击值
int x1[N], y1[N], z1[N]; // 存储攻击范围,即区间修改范围(x1,y1,z1) --- (x2,y2,z2)
int x2[N], y2[N], z2[N];
int d[N]; // 记录每次伤害
int num(int x, int y, int z)
{
if (x > A || y > B || z > C)
{
return 0;
}
return ((x - 1) * B + (y - 1)) * C + (z - 1) + 1;
}
bool check(int x)
{ // x次区间修改与检查
for (int i = 1; i <= n; i++)
{
D[i] = 0; // 差分数组初始化
}
for (int i = 1; i <= x; i++)
{ // 8个区间端点的修改
D[num(x1[i], y1[i], z1[i])] += d[i];
D[num(x2[i] + 1, y1[i], z1[i])] -= d[i];
D[num(x1[i], y1[i], z2[i] + 1)] -= d[i];
D[num(x2[i] + 1, y1[i], z2[i] + 1)] += d[i];
D[num(x1[i], y2[i] + 1, z1[i])] -= d[i];
D[num(x2[i] + 1, y2[i] + 1, z1[i])] += d[i];
D[num(x1[i], y2[i] + 1, z2[i] + 1)] += d[i];
D[num(x2[i] + 1, y2[i] + 1, z2[i] + 1)] -= d[i];
}
// 分别从x,y,z方向计算前缀和
for (int i = 1; i <= A; i++)
for (int j = 1; j <= B; j++)
for (int k = 1; k < C; k++)
{
D[num(i, j, k + 1)] += D[num(i, j, k)];
}
for (int i = 1; i <= A; i++)
for (int k = 1; k <= C; k++)
for (int j = 1; j < B; j++)
{
D[num(i, j + 1, k)] += D[num(i, j, k)];
}
for (int k = 1; k <= C; k++)
for (int j = 1; j <= B; j++)
for (int i = 1; i < A; i++)
{
D[num(i + 1, j, k)] += D[num(i, j, k)];
}
for (int i = 1; i <= n; i++)
{ // 判断攻击值是否大于生命值
if (D[i] > s[i])
return true;
}
return false;
}
int main(){
scanf("%d%d%d%d", &A, &B, &C, &m);
n = A * B * C;
for (int i = 1; i <= n; i++)//读入舰队生命值
scanf("%d", &s[i]);
for (int i = 1; i <= m; i++){//m次攻击
scanf("%d%d%d%d%d%d%d", &x1[i], &x2[i], &y1[i], &y2[i], &z1[i], &z2[i], &d[i]);
}
int L = 1;
int R = m;
while(L < R){//二分
int mid = (L + R) >> 1;
if(check(mid)){
R = mid;
}
else
L = mid + 1;
}
printf("%d\n", R);
return 0;
}
文章介绍了如何通过编程解决一个关于三体攻击的计算问题,涉及舰队布局、生命值计算和二分搜索方法确定首艘爆炸战舰的攻击轮数。
7066





