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

· · 题解

在 12 月 30 日更新。

先看下题目。

这题其实就是一个修改问题,每次修改一个部分,看第几次有一个战舰累计受到的总伤害超过其防御力,就输出这个攻击的轮数。

我们读完题,会发现这道题其实具有单调性。为什么呢?因为操作轮数越多,有某一个船爆炸的概率就越大。所以可以二分答案。

l=1;
r=m;
while (l<=r)
{
    mid=l+r>>1;
    if (check(mid)) r=mid-1;
    else l=mid+1;
}

那么怎么检查呢?这就用到了三维差分。

三维差分怎么做?我们先来看看一维和二维的我们是怎么做的。

一维:

a[s]+=h;
a[t+1]-=h;

二维(奇减偶加):

b[sx][sy]+=h;
b[sx][ty+1]-=h;
b[tx+1][sy]-=h;
b[tx+1][ty+1]+=h;

由此,我们根据容斥原理,发现三维的是奇加偶减,可得三维差分公式:

c[calc(sx,sy,sz)]+=h;
c[calc(tx+1,sy,sz)]-=h;
c[calc(sx,ty+1,sz)]-=h;
c[calc(sx,sy,tz+1)]-=h;
c[calc(sx,ty+1,tz+1)]+=h;
c[calc(tx+1,sy,tz+1)]+=h;
c[calc(tx+1,ty+1,sz)]+=h;
c[calc(tx+1,ty+1,tz+1)]-=h;

在做完差分后,再求前缀和(容斥原理,奇加偶减)。

c[calc(i,j,k)]+=
c[calc(i-1,j,k)]
+c[calc(i,j-1,k)]
+c[calc(i,j,k-1)]
-c[calc(i-1,j-1,k)]
-c[calc(i-1,j,k-1)]
-c[calc(i,j-1,k-1)]
+c[calc(i-1,j-1,k-1)];

计算函数指的是把三维压成一维,映射它在一维数组中的位置。

int calc(int a,int b,int c)
{
    return max(0ll,((a-1)*B+(b-1))*C+(c-1)+1);
                |
          防越界
}

最后,展示。

注意 HACK 数据。