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

文章介绍了如何通过编程解决一个关于三体攻击的计算问题,涉及舰队布局、生命值计算和二分搜索方法确定首艘爆炸战舰的攻击轮数。

[蓝桥杯 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

三维差分+压维+二分

 #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;
}
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值